ONT 16S Sequencing Files
Raw fast5 files from each Oxford Nanopore (ONT) sequencing batch can
be found within the directory named: raw_fast5_files/
A total of 8 sequencing batches were run. Each
batch includes 24 samples from the following treatment and donor
ids:
      1. UT1, UT2, UT3
      2. UT4, UT5, UT6
      3. PLA1, PLA2, PLA3
      4. PLA4, PLA5, PLA6 *NOTE: These samples
had to be re-run so they represent two separate sequencing runs
      5. T1-1, T1-2, T1-3
      6. T1-4, T1-5, T1-6
      7. T2-1, T2-2, T2-3
      8. T2-4, T2-5, T2-6
So for example, the raw fast5 files of samples
within UT1, UT2, UT3 would be in:
raw_fast5_files/UT1_UT2_UT3_fast5s/
ONT 16S Sequence QC Pipeline
After ONT sequencing the following pipeline was
used to demultiplex and quality filter reads:
      Chopper parameters used:
          • Min q score: 10
          • Min length: 1,000 bp
          • Head crop: 50
          • Max length: 1690
4. Multiqc results summary using fastp qc V
0.20.1
   Multiqc results for each sequencing batch can be found in the
directory named: multiqc
Statistical Analysis
Diversity, differential abundance, and relative abundance of taxa
were analyzed via Phyloseq and statistical tests were run between the 4
treatments.
The biom file and metadata table imported into phyloseq can be found
in the directory named: stats_analysis
Results include:
o Alpha diversity metrics - Observed, Shannon,
Simpson (csv tables in stats_analysis directory)
o Alpha diversity statistical tests (results
below)
o Alpha diversity boxplots (tiff images in
stats_analysis/alpha_diversity_plots directory)
      • *NOTE: Observed richness was run on raw
and normalized data. Rarefaction to lowest read number was used as
normalization.
      This was included for comparative purposes. Other normalization
methods can also be run if requested.
o Pairwise differential abundance test via
DeSeq2 (csv table results in stats_analysis/DESEQ2 directory)
      • Volcano plot (tiff image in
stats_analysis/DESEQ2 directory)
o Beta diversity statistical tests -
Bray-Curtis, Euclidean distances
o Beta diversity plots (tiff images in
stats_analysis/beta_diversity_plots directory)
o Relative abundance taxa plots (tiff images can
be found in stats_analysis/taxaplots directory)
#Libraries we will use
library("DESeq2")
library("ggplot2")
library(Biostrings)
library("phyloseq")
library("microbiome")
library("ggthemes")
library(ggnetwork)
library(cowplot)
library("vegan")
library(magrittr)
library(dplyr)
library(EnhancedVolcano)
#Create a few output directories that will hold the output files.
dir.create('./DESEQ2')
dir.create('./ANCOM')
# Load data and add metadata
ps_object <- import_biom("./HOMD_biom_merge.biom")
#import medata and add to phyloseq object
metadata <- read.csv("./metadata.csv", row.names = 1)
metadata = sample_data(data.frame(metadata))
sample_data(ps_object) <- metadata
Statistical Analysis Results
Total number of taxa
The total number of taxonomically identified ASVs across all
samples
#Check sample numbers
ntaxa(ps_object) #Total taxa
[1] 535
Number of taxonomically classified reads per sample
Samples will have varying numbers of taxonomically classified reads
due to different sampling depths during sequencing.
#Check sample numbers
sample_sums(ps_object) #Reads per sample
PLA-6G.trim.fastq_bracken PLA-5F.trim.fastq_bracken PLA-6D.trim.fastq_bracken PLA-6E.trim.fastq_bracken
122253 134537 151338 160823
PLA-4G.trim.fastq_bracken T1-6D.trim.fastq_bracken PLA-5H.trim.fastq_bracken PLA-6F.trim.fastq_bracken
134896 252097 164959 111641
T1-6E.trim.fastq_bracken PLA-4F.trim.fastq_bracken T1-5E.trim.fastq_bracken PLA-4D.trim.fastq_bracken
218460 261085 327649 193079
T1-5F.trim.fastq_bracken T1-5D.trim.fastq_bracken T1-4A.trim.fastq_bracken PLA-5A.trim.fastq_bracken
269287 296705 332687 141418
PLA-5G.trim.fastq_bracken T1-6H.trim.fastq_bracken PLA-5B.trim.fastq_bracken T1-5G.trim.fastq_bracken
244555 219936 271721 281291
PLA-6B.trim.fastq_bracken T1-6G.trim.fastq_bracken PLA-4C.trim.fastq_bracken PLA-4A.trim.fastq_bracken
196991 217395 308241 314998
T1-4H.trim.fastq_bracken T1-6F.trim.fastq_bracken T1-6A.trim.fastq_bracken T1-4B.trim.fastq_bracken
276626 205810 229874 340421
T1-5H.trim.fastq_bracken PLA-4E.trim.fastq_bracken T1-6C.trim.fastq_bracken T1-5C.trim.fastq_bracken
307412 185855 202763 291410
PLA-6H.trim.fastq_bracken T2-4A.trim.fastq_bracken T2-6F.trim.fastq_bracken T2-5D.trim.fastq_bracken
124695 177019 121162 149516
PLA-5C.trim.fastq_bracken T1-4G.trim.fastq_bracken T2-4C.trim.fastq_bracken T2-4B.trim.fastq_bracken
115282 229188 175811 166040
T2-5A.trim.fastq_bracken PLA-6C.trim.fastq_bracken PLA-5D.trim.fastq_bracken PLA-5E.trim.fastq_bracken
143238 149583 148025 147511
T2-4G.trim.fastq_bracken PLA-4B.trim.fastq_bracken T1-6B.trim.fastq_bracken T2-5E.trim.fastq_bracken
122305 307852 233657 230137
T2-5C.trim.fastq_bracken T2-4F.trim.fastq_bracken T2-6H.trim.fastq_bracken T2-6E.trim.fastq_bracken
135595 136812 122927 114585
T2-6G.trim.fastq_bracken PLA-4H.trim.fastq_bracken T2-5F.trim.fastq_bracken T2-6C.trim.fastq_bracken
111199 232902 117429 99830
T2-6A.trim.fastq_bracken T2-4H.trim.fastq_bracken T2-5G.trim.fastq_bracken T1-1E.trim.fastq_bracken
134098 139078 141449 129593
T1-4F.trim.fastq_bracken T2-4E.trim.fastq_bracken T2-6D.trim.fastq_bracken T2-5B.trim.fastq_bracken
291101 158881 111618 156670
T2-5H.trim.fastq_bracken T1-4E.trim.fastq_bracken T1-5A.trim.fastq_bracken T1-5B.trim.fastq_bracken
146811 320326 295293 335887
T1-2C.trim.fastq_bracken PLA-2A.trim.fastq_bracken T1-1H.trim.fastq_bracken T1-2F.trim.fastq_bracken
112517 129688 112481 111566
T1-3D.trim.fastq_bracken T1-1A.trim.fastq_bracken T1-1D.trim.fastq_bracken T1-1B.trim.fastq_bracken
137279 156574 156381 142894
T1-3B.trim.fastq_bracken T1-3E.trim.fastq_bracken T1-3F.trim.fastq_bracken T1-2E.trim.fastq_bracken
143554 136304 126753 137682
T1-2G.trim.fastq_bracken T1-2D.trim.fastq_bracken T2-6B.trim.fastq_bracken PLA-6A.trim.fastq_bracken
138687 135530 107692 221393
T2-4D.trim.fastq_bracken T1-4D.trim.fastq_bracken T1-4C.trim.fastq_bracken T1-1G.trim.fastq_bracken
186787 516674 347729 97588
T1-2H.trim.fastq_bracken T1-1F.trim.fastq_bracken T1-2B.trim.fastq_bracken T1-1C.trim.fastq_bracken
132909 100480 169725 150087
T1-3G.trim.fastq_bracken T1-3H.trim.fastq_bracken T1-2A.trim.fastq_bracken T1-3C.trim.fastq_bracken
132758 137643 121393 134268
PLA-1H.trim.fastq_bracken T1-3A.trim.fastq_bracken PLA-1A.trim.fastq_bracken PLA-1C.trim.fastq_bracken
113231 164631 150169 136540
PLA-3D.trim.fastq_bracken PLA-3C.trim.fastq_bracken PLA-3A.trim.fastq_bracken PLA-3E.trim.fastq_bracken
128055 127764 152664 137933
PLA-3H.trim.fastq_bracken PLA-1G.trim.fastq_bracken UT-5C.trim.fastq_bracken PLA-2F.trim.fastq_bracken
139049 113533 142315 116570
PLA-2D.trim.fastq_bracken PLA-2C.trim.fastq_bracken PLA-3B.trim.fastq_bracken PLA-2E.trim.fastq_bracken
119736 124253 121101 141694
PLA-1E.trim.fastq_bracken PLA-2H.trim.fastq_bracken PLA-3G.trim.fastq_bracken PLA-1B.trim.fastq_bracken
139254 124653 134659 139846
PLA-2G.trim.fastq_bracken PLA-3F.trim.fastq_bracken UT-6B.trim.fastq_bracken UT-6G.trim.fastq_bracken
131090 124131 149386 157610
UT-4B.trim.fastq_bracken UT-5E.trim.fastq_bracken PLA-2B.trim.fastq_bracken UT-4A.trim.fastq_bracken
188401 204864 147226 232458
UT-4D.trim.fastq_bracken PLA-1D.trim.fastq_bracken UT-4G.trim.fastq_bracken PLA-1F.trim.fastq_bracken
230691 170659 146773 114481
UT-4E.trim.fastq_bracken UT-6E.trim.fastq_bracken UT-6F.trim.fastq_bracken UT-5D.trim.fastq_bracken
180292 160952 150999 161566
UT-5F.trim.fastq_bracken UT-5B.trim.fastq_bracken UT-6C.trim.fastq_bracken UT-4H.trim.fastq_bracken
162768 194116 137967 148853
UT-5G.trim.fastq_bracken UT-5A.trim.fastq_bracken UT-4C.trim.fastq_bracken UT-4F.trim.fastq_bracken
155111 166610 210096 174867
UT-5H.trim.fastq_bracken UT-6H.trim.fastq_bracken T2-2C.trim.fastq_bracken T2-2H.trim.fastq_bracken
171615 155942 224131 236759
T2-1F.trim.fastq_bracken T2-3D.trim.fastq_bracken UT-6A.trim.fastq_bracken UT-6D.trim.fastq_bracken
220654 226536 150983 154152
T2-2D.trim.fastq_bracken T2-1G.trim.fastq_bracken T2-1D.trim.fastq_bracken T2-3G.trim.fastq_bracken
212920 196370 254486 241081
T2-3C.trim.fastq_bracken T2-1C.trim.fastq_bracken T2-2B.trim.fastq_bracken T2-1B.trim.fastq_bracken
244282 288104 247158 265356
T2-3A.trim.fastq_bracken T2-3F.trim.fastq_bracken T2-2E.trim.fastq_bracken UT3D.trim.fastq_bracken
254775 249430 228892 193130
T2-3B.trim.fastq_bracken T2-2G.trim.fastq_bracken T2-3E.trim.fastq_bracken T2-1A.trim.fastq_bracken
258304 236985 230370 239366
T2-2F.trim.fastq_bracken T2-1E.trim.fastq_bracken T2-1H.trim.fastq_bracken T2-2A.trim.fastq_bracken
197203 251642 212102 219040
UT3B.trim.fastq_bracken UT2C.trim.fastq_bracken UT2B.trim.fastq_bracken UT1E.trim.fastq_bracken
303307 119023 90053 95039
UT1H.trim.fastq_bracken UT2A.trim.fastq_bracken T2-3H.trim.fastq_bracken UT1F.trim.fastq_bracken
85347 94188 246493 103031
UT1G.trim.fastq_bracken UT1B.trim.fastq_bracken UT2H.trim.fastq_bracken UT1A.trim.fastq_bracken
90941 251468 131175 215807
UT2E.trim.fastq_bracken UT3C.trim.fastq_bracken UT2G.trim.fastq_bracken UT3G.trim.fastq_bracken
174982 159762 230766 293498
UT1D.trim.fastq_bracken UT2F.trim.fastq_bracken UT3H.trim.fastq_bracken UT3E.trim.fastq_bracken
146254 257994 263981 195541
UT2D.trim.fastq_bracken UT3F.trim.fastq_bracken UT3A.trim.fastq_bracken UT1C.trim.fastq_bracken
255864 276688 284484 290816
Alpha Diversity
Measuring species diversity within each sample.
#Function to calculate the mean and the standard deviation for each group.
#data : a data frame
#varname : the name of a column containing the variable to be summarized
#groupnames : vector of column names to be used as grouping variables
# Calculate standard error
sderr <- function(x) {sd(x)/sqrt(length(x))}
data_summary <- function(data, varname, groupnames){
require(plyr)
summary_func <- function(x, col){
c(mean = mean(x[[col]], na.rm=TRUE),
sd = sderr(x[[col]]), na.rm=TRUE)
}
data_sum<-ddply(data, groupnames, .fun=summary_func,
varname)
data_sum <- rename(data_sum, c("mean" = varname))
return(data_sum)
}
Data table with alpha diversity metrics: Observed, Shannon,
Simpson
Example of data table structure (full table saved as csv)
Three alpha diversity metrics are calculated for each sample. The
full table (per_sample_ad_dataframe.csv) can be found in the directory
named: stats_analysis
alpha_div <- cbind(estimate_richness(ps_object,
measures = c('Observed', 'Shannon', 'Simpson')),
sample_data(ps_object))
colnames(alpha_div) <- c('Observed', 'Shannon', 'Simpson')
alpha_div$Labels <- rownames(alpha_div)
ad_df <- alpha_div[,c('Observed', 'Shannon', 'Simpson')]
ad_df <- cbind(ad_df,
sample_data(ps_object)[, c('sample', 'group', 'donor', 'treatment')])
colnames(ad_df) <- c('Observed', 'Shannon', 'Simpson', 'sample', 'group', 'donor', 'treatment')
head(ad_df)
write.csv(ad_df, "./per_sample_ad_dataframe.csv")
Data Summary statistics: Observed, Shannon, Simpson
Summary for each treatment
The average of each alpha diversity metric for all samples within a
treatment.
# Observed
data_summary(ad_df, varname = "Observed", groupnames = c("treatment"))
#data_summary(ad_df, varname = "Observed", groupnames = c("sample"))
#data_summary(ad_df, varname = "Observed", groupnames = c("donor"))
# Shannon
data_summary(ad_df, varname = "Shannon", groupnames = c("treatment"))
#data_summary(ad_df, varname = "Shannon", groupnames = c("sample"))
#data_summary(ad_df, varname = "Shannon", groupnames = c("donor"))
# Simpson
data_summary(ad_df, varname = "Simpson", groupnames = c("treatment"))
#data_summary(ad_df, varname = "Simpson", groupnames = c("sample"))
#data_summary(ad_df, varname = "Simpson", groupnames = c("donor"))
Alpha diversity statistical tests for significance
Kruskal Wallis and Pairwise Wilcoxon tests
Kruskal-Wallis Rank Sum Test for a category (treatment) on each Alpha
Diversity metric calculated. This is a non-parametric method which ranks
the data and tests whether samples from each group analyzed come from
the same distribution.
Pairwise Wilcoxon Rank Sum Test between groups within a category
(treatment) on each Alpha Diversity metric calculated and corrected for
multiple testing. This methods compares two independent samples for all
group levels and includes the false discovery rate (FDR) multiple test
correction. The results below come up as a matrix filled with the
p-values for each treatment comparison.
Observed Richness
Testing ASV/species richness between the 4 treatments.
#### Observed
#Kruskal Wallis tests
kruskal.test(Observed ~ treatment, data = ad_df)
Kruskal-Wallis rank sum test
data: Observed by treatment
Kruskal-Wallis chi-squared = 11.944, df = 3, p-value = 0.007577
#kruskal.test(Observed ~ sample, data = ad_df)
#kruskal.test(Observed ~ donor, data = ad_df)
#Pairwise Wilcoxon Test
pairwise.wilcox.test(ad_df$Observed, ad_df$treatment, p.adjust.method = 'fdr')
Pairwise comparisons using Wilcoxon rank sum test with continuity correction
data: ad_df$Observed and ad_df$treatment
1.5R 8R Placebo
8R 0.849 - -
Placebo 0.179 0.257 -
Untreated 0.179 0.011 0.011
P value adjustment method: fdr
Shannon Diversity
Testing ASV/species richness between the 4 treatments while also
taking into account relative abundance (evenness).
#### Shannon
#Kruskal Wallis tests
kruskal.test(Shannon ~ treatment, data = ad_df)
Kruskal-Wallis rank sum test
data: Shannon by treatment
Kruskal-Wallis chi-squared = 6.9716, df = 3, p-value = 0.07281
#kruskal.test(Shannon ~ sample, data = ad_df)
#kruskal.test(Shannon ~ donor, data = ad_df)
#Pairwise Wilcoxon Test
pairwise.wilcox.test(ad_df$Shannon, ad_df$treatment, p.adjust.method = 'fdr')
Pairwise comparisons using Wilcoxon rank sum exact test
data: ad_df$Shannon and ad_df$treatment
1.5R 8R Placebo
8R 0.73 - -
Placebo 0.92 0.64 -
Untreated 0.11 0.17 0.10
P value adjustment method: fdr
Simpson Diversity
Testing ASV/species richness between the 4 treatments while also
taking into account relative abundance (evenness). Simpson diversity
gives more weight to common or dominant ASVs (rare ASVs will not affect
diversity).
#### Simpson
#Kruskal Wallis tests
kruskal.test(Simpson ~ treatment, data = ad_df)
Kruskal-Wallis rank sum test
data: Simpson by treatment
Kruskal-Wallis chi-squared = 3.2214, df = 3, p-value = 0.3587
#kruskal.test(Simpson ~ sample, data = ad_df)
#kruskal.test(Simpson ~ donor, data = ad_df)
#Pairwise Wilcoxon Test
pairwise.wilcox.test(ad_df$Simpson, ad_df$treatment, p.adjust.method = 'fdr')
Pairwise comparisons using Wilcoxon rank sum exact test
data: ad_df$Simpson and ad_df$treatment
1.5R 8R Placebo
8R 0.60 - -
Placebo 0.80 0.60 -
Untreated 0.60 0.60 0.48
P value adjustment method: fdr
Alpha diversity boxplots
Images of each plot can be found in:
stats_analysis/alpha_diversity_plots
###Group plots
#Observed
obs_ad_plot <- ggplot(ad_df, aes(x=treatment, y=Observed, color = treatment)) + geom_boxplot() + geom_point() + ylab('Observed Richness') + scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F"))
obs_ad_plot

ggsave("obs_ad_plot.tiff", dpi = 300, plot = obs_ad_plot, path = "./alpha_diversity_plots/")
#Shannon
shan_ad_plot <- ggplot(ad_df, aes(x=treatment, y=Shannon, color = treatment)) + geom_boxplot() + geom_point() + ylab('Shannon Diversity') + scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F"))
shan_ad_plot

ggsave("shan_ad_plot.tiff", dpi = 300, plot = shan_ad_plot, path = "./alpha_diversity_plots/")
#Simpson
simp_ad_plot <- ggplot(ad_df, aes(x=treatment, y=Simpson, color = treatment)) + geom_boxplot() + geom_point() + ylab('Simpson Diversity') + scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F"))
simp_ad_plot

ggsave("simp_ad_plot.tiff", dpi = 300, plot = simp_ad_plot, path = "./alpha_diversity_plots/")
Alpha Diversity on Rarefied Data
Normalize Observed Richness metric by rarefying to lowest sample sum
number
Shannon and Simpson diversity indices are already normalized by
relative abundance.
Rarefaction read depth
One method of normalization is to rarefy each sample to the minimum
read depth found across all samples. The minimum read depth for all
samples is:
min(sample_sums(ps_object)) #Minimum reads (used for rarefying)
[1] 85347
Example of datatable structure for rarefied data observed richness
(full table saved as csv)
Observed richness is calculated for each sample now rarefied to the
minimum read depth. The full table
(rarefied_per_sample_ad_dataframe.csv) can be found in the directory
named: stats_analysis
#Rarefy to lowest sample_sums
rare_num <- min(sample_sums(ps_object))
ps_rare <- rarefy_even_depth(ps_object, sample.size = rare_num, rngseed = 999)
#Get datatable with Observed richness for rarefied samples
alpha_div_rare <- cbind(estimate_richness(ps_rare,
measures = c('Observed')),
sample_data(ps_rare))
colnames(alpha_div_rare) <- c('Observed_rare')
alpha_div_rare$Labels <- rownames(alpha_div_rare)
ad_df_rare <- alpha_div_rare[,c('Observed_rare')]
ad_df_rare <- cbind(ad_df_rare,
sample_data(ps_rare)[, c('sample', 'group', 'donor', 'treatment')])
colnames(ad_df_rare) <- c('Observed_rare', 'sample', 'group', 'donor', 'treatment')
head(ad_df_rare)
write.csv(ad_df_rare, "./rarefied_per_sample_ad_dataframe.csv")
Data summary for rarefied data (observed richness)
The average observed richness for all samples within a treatment.
# Observed Rarefied data summary stats
data_summary(ad_df_rare, varname = "Observed_rare", groupnames = c("treatment"))
#data_summary(ad_df_rare, varname = "Observed_rare", groupnames = c("sample"))
#data_summary(ad_df_rare, varname = "Observed_rare", groupnames = c("donor"))
Observed richness statistical tests for rarefied data
Testing ASV/species richness between the 4 treatments.
#### Observed Rarefied
#Kruskal Wallis tests
kruskal.test(Observed_rare ~ treatment, data = ad_df_rare)
Kruskal-Wallis rank sum test
data: Observed_rare by treatment
Kruskal-Wallis chi-squared = 12.925, df = 3, p-value = 0.004801
#kruskal.test(Observed_rare ~ sample, data = ad_df_rare)
#kruskal.test(Observed_rare ~ donor, data = ad_df_rare)
#Pairwise Wilcoxon Test
pairwise.wilcox.test(ad_df_rare$Observed_rare, ad_df_rare$treatment, p.adjust.method = 'fdr')
Pairwise comparisons using Wilcoxon rank sum test with continuity correction
data: ad_df_rare$Observed_rare and ad_df_rare$treatment
1.5R 8R Placebo
8R 0.6733 - -
Placebo 0.3884 0.6733 -
Untreated 0.0635 0.0066 0.0066
P value adjustment method: fdr
Rarefied data observed richness boxplot
Images of the plot can be found in:
stats_analysis/alpha_diversity_plots
#Plots: Observed Rarefied
obs_ad_plot_rare <- ggplot(ad_df_rare, aes(x=treatment, y=Observed_rare, color = treatment)) + geom_boxplot() + geom_point() + ylab('Observed Richness Rarefied Data') + scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F"))
obs_ad_plot_rare

ggsave("rarefied_obs_ad_plot.tiff", dpi = 300, plot = obs_ad_plot_rare, path = "./alpha_diversity_plots/")
Differential Abundance Analysis
Pairwise differential abundance test between treatments via
DESeq2
The package DESeq2 provides methods to test for differential
abundance by use of negative binomial generalized linear models. DESeq2
uses the Wald test to take into account the dispersion model distance
and negative binomial distribution we see in sequencing data. Overall
this method statistically infers systematic changes between conditions,
as compared to within-condition variability. It estimates dispersion and
logarithmic fold changes to test which sequences/ASVs are significantly
changing within the experimental design.
Additionally, a p-value correction is applied for multiple hypothesis
testing. Traditionally p < 0.05 is considered significant (95% chance
it is not by random chance), but when you are looking at thousands of
ASVs/sequences, you’ll still end up with 5% of them significant off
predicted chance. One of the best corrections to use called
False-Discovery Rate correction (FDR), which is the Benjamini and
Hochberg method.
Here we ran DESeq2 specifying only treatment in the experimental
design. Log fold changes and adjusted p-valus (padj) for all ASVs and
significant ASVs have been saved as csv tables in the
stats_analysis/DESEQ2 directory (named dds_result_table.csv and
sig_result_table.csv respectively).
The below plot shows the fitted curve (red line) used to calculate
the final dispersion estimates (blue dots) of the input data (black
dots).
#Phyloseq to Deseq2
ps_deseq = phyloseq_to_deseq2(ps_object, ~treatment)
#Run Deseq2
dds = DESeq(ps_deseq, test="Wald", fitType="local")
dds_result <- results(dds)
dds_result_table <- cbind(as(dds_result, "data.frame"), as(tax_table(ps_object)[rownames(dds_result), ], "matrix"))
write.csv(dds_result_table, "./DESEQ2/dds_result_table.csv")
#check significant results
dds_sig = dds_result[which(dds_result$padj < 0.05), ]
dds_sig_table = cbind(as(dds_sig, "data.frame"), as(tax_table(ps_object)[rownames(dds_sig), ], "matrix"))
dim(dds_sig_table)
write.csv(dds_sig_table, "./DESEQ2/sig_result_table.csv")
#Perform the variance stabilizing transformation on the data and pull the normalized hit count matrix.
vst <- varianceStabilizingTransformation(dds)
mat <- assay(vst)
#If you have a batch designed in, regress the batch effects.
#mat <- limma::removeBatchEffect(mat, vst$batch)
#assay(vst) <- mat
#Plot the overall dispersion of the experiment to ensure it aligns with expectations.
plotDispEsts(dds)

Volcano plot: DeSeq2 results
Volcano plots are a great way to visualize the pairwise comparisons.
Each shows the log2 fold-change (log2FC) on the x-axis and -log10(padj)
on the y-axis. This should usually look akin to a Plinian eruption
(hence volcano plot).
Image of the volcano plot can be found in the stats_analysis/DESEQ2/
directory
p <- EnhancedVolcano(dds_result_table,
lab=as.character(dds_result_table$Rank9),
title="Pairwise comparisons of taxa (species level) between treatments",
x='log2FoldChange',
y='padj',
legendPosition = 'bottom',
legendLabels=c('Not sig.','Log (base 2) FC','padj-value','padj-value & Log (base 2) FC'),
pCutoff=0.05,
FCcutoff=1
)
print(p)

ggsave("volcano_plot.tiff", dpi = 300, plot = p, path = "./DESEQ2/")
Beta Diversity
Measuring species diversity or the level or similarity/dissimilarity
of species between samples.
#Pairwise Adonis function
pairwise.adonis.dm <- function(x,factors,stratum=NULL,p.adjust.m="fdr",perm=999){
library(vegan)
if(class(x) != "dist") stop("x must be a dissimilarity matrix (dist object)")
co = as.matrix(combn(unique(factors),2))
pairs = c()
F.Model =c()
R2 = c()
p.value = c()
for(elem in 1:ncol(co)){
sub_inds <- factors %in% c(as.character(co[1,elem]),as.character(co[2,elem]))
resp <- as.matrix(x)[sub_inds,sub_inds]
ad = adonis2(as.dist(resp) ~
factors[sub_inds], strata=stratum[sub_inds], permutations=perm);
pairs = c(pairs,paste(co[1,elem],'vs',co[2,elem]));
F.Model =c(F.Model,ad$F[1]);
R2 = c(R2,ad$R2[1]);
p.value = c(p.value,ad$`Pr(>F)`[1])
}
p.adjusted = p.adjust(p.value,method=p.adjust.m)
pairw.res = data.frame(pairs,F.Model,R2,p.value,p.adjusted)
return(pairw.res)
}
# Calculate distance matrices
ps_bc <- phyloseq::distance(ps_object, method = "bray")
ps_euc <- phyloseq::distance(ps_object, method = "euclidean")
PERMANOVAs
PERMANOVA’s with Adonis - Permutational Multivariate Analysis of
Variance. This measures dissimilarity in response to one or more factors
in an analysis of variance design. Dissimilarity statistics are used to
measure distances between data points and test whether they are
significantly different.
We run the Adonis test specifying the treatment groups in the model
formula.
Bray-curtis
Bray-Curtis dissimilarity examines the abundances of ASVs that are
shared between two samples, and the number of ASVs found in each.
Bray-Curtis dissimilarity ranges from 0-1. If 0, the two samples share
all the same ASVs; if 1, they don’t share any ASVs.
Permanova result
The value under the column labeled ‘Pr(>F)’ in the results table
indicates significance (i.e. p-value)
#make a dataframe out of the sample data
sampledf <- data.frame(sample_data(ps_object))
adonis2(ps_bc ~ treatment, data = sampledf)
Permutation test for adonis under reduced model
Terms added sequentially (first to last)
Permutation: free
Number of permutations: 999
adonis2(formula = ps_bc ~ treatment, data = sampledf)
Df SumOfSqs R2 F Pr(>F)
treatment 3 1.026 0.02703 1.7409 0.062 .
Residual 188 36.936 0.97297
Total 191 37.962 1.00000
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Euclidean
Measures the distance between two samples in Euclidean space (the
length of the line segment between them).
Permanova result
The value under the column labeled ‘Pr(>F)’ in the results table
indicates significance (i.e. p-value)
adonis2(ps_euc ~ treatment, data = sampledf)
Permutation test for adonis under reduced model
Terms added sequentially (first to last)
Permutation: free
Number of permutations: 999
adonis2(formula = ps_euc ~ treatment, data = sampledf)
Df SumOfSqs R2 F Pr(>F)
treatment 3 3.0164e+10 0.03385 2.1953 0.008 **
Residual 188 8.6105e+11 0.96615
Total 191 8.9121e+11 1.00000
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Pairwise comparisons
A multi-level Adonis test using the FDR multiple test correction.
Bray-curtis pairwise result
pairwise.adonis.dm(ps_bc, sampledf$treatment, p.adjust.m = "fdr")
NA
Euclidean pairwise result
pairwise.adonis.dm(ps_euc, sampledf$treatment, p.adjust.m = "fdr")
NA
Beta diversiy PCoA and NMDS plots
PCoA and NMDS plots are used to visualize the
similarities/dissimilarities of sample points using their calculated
distance/dissimilarity matrices (from the Bray-curtis and Euclidean
distance measurements). Samples that are closer are more related and
vice versa. PCoA plots maximize the linear correlation between samples,
wherein NMDS plots maximize the rank-order correlation between samples.
Additionally, in case of NMDS, data is not required to fit a normal
distribution.
Images of each plot can be found in the
stats_analysis/beta_diversity_plots/ directory.
Bray-curtis PCoA
# Bray-curtis
#PCOA BC
ps_bc_pcoa <- ordinate(ps_object, distance = ps_bc, "PCoA")
ps_bc_pcoa_plot <- plot_ordination(ps_object, ps_bc_pcoa, color = "treatment") +
geom_point(size = 3) +
theme_classic() +
theme(legend.position = "bottom", legend.title = element_blank()) +
scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F")) +
theme(plot.title = element_text(hjust = 0.5))
ps_bc_pcoa_plot

#save as tiff
ggsave("bray_pcoa_plot.tiff", dpi = 300, plot = ps_bc_pcoa_plot, path = "./beta_diversity_plots/")
Bray-curtis NMDS
#NMDS BC
ps_bc_nmds <- ordinate(ps_object, distance = ps_bc, "NMDS")
ps_bc_nmds_plot <- plot_ordination(ps_object, ps_bc_nmds, color = "treatment") +
geom_point(size = 3) +
theme_classic() +
theme(legend.position = "bottom", legend.title = element_blank()) +
scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F")) +
theme(plot.title = element_text(hjust = 0.5))
ps_bc_nmds_plot

#save as tiff
ggsave("bray_nmds_plot.tiff", dpi = 300, plot = ps_bc_nmds_plot, path = "./beta_diversity_plots/")
Euclidean PCoA
# Euclidean
#PCOA EUC
ps_euc_pcoa <- ordinate(ps_object, distance = ps_euc, "PCoA")
ps_euc_pcoa_plot <- plot_ordination(ps_object, ps_euc_pcoa, color = "treatment") +
geom_point(size = 3) +
theme_classic() +
theme(legend.position = "bottom", legend.title = element_blank()) +
scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F")) +
theme(plot.title = element_text(hjust = 0.5))
ps_euc_pcoa_plot

#save as tiff
ggsave("euc_pcoa_plot.tiff", dpi = 300, plot = ps_euc_pcoa_plot, path = "./beta_diversity_plots/")
Euclidean NMDS
#NMDS BC
ps_euc_nmds <- ordinate(ps_object, distance = ps_euc, "NMDS")
ps_euc_nmds_plot <- plot_ordination(ps_object, ps_euc_nmds, color = "treatment") +
geom_point(size = 3) +
theme_classic() +
theme(legend.position = "bottom", legend.title = element_blank()) +
scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F")) +
theme(plot.title = element_text(hjust = 0.5))
ps_euc_nmds_plot

#save as tiff
ggsave("euc_nmds_plot.tiff", dpi = 300, plot = ps_euc_nmds_plot, path = "./beta_diversity_plots/")
Relative Abundance Taxa Plots
Relative abundance taxa bar plots for treatment
Plots were made at the phylum, genus, and species level, comparing
across the 4 treatments.
Images of each plot can be found in the stats_analysis/taxaplots/
directory.
Phylum
# transform to relative abundance
ps_rel <- transform(ps_object, "compositional")
# melt the data into a table
ps_rel_melt<- ps_rel %>%
psmelt()
# Get phylum with mean relative abundance across all samples
ps_rel_phylum_sum <- ps_rel_melt%>% group_by(Rank3) %>% dplyr::summarise(Aver = mean(Abundance))
names_ps_rel_phylum <- ps_rel_phylum_sum$Rank3
names_ps_rel_phylum
#Phylum Plot
taxaplot_ps_rel_phylum = ggplot(ps_rel_melt
, aes(x = treatment, y=Abundance)) +
geom_bar(stat="identity", position="fill", aes(fill = Rank3)) +
scale_fill_manual(values=c("aquamarine4", "gold","lightpink", "firebrick","#DA5724","ivory4",
"orchid", "#CBD588", "#8569D5", "#D14285", "#652926","grey80",
"#5E738F","#D1A33D", "#8A7C64","lightgreen","aquamarine4",
"aquamarine2", "lightsalmon", "#CD9BCD")) +
theme_bw() +
ylab("Relative Abundance") + xlab("Treatment") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0))
taxaplot_ps_rel_phylum <- taxaplot_ps_rel_phylum + guides(fill=guide_legend(title="Phylum"))
taxaplot_ps_rel_phylum

ggsave("taxaplot_phylum.tiff", dpi = 300, plot = taxaplot_ps_rel_phylum, path = "./taxaplots/")
Genus
Genera with a relative abundance lower than 0.0001 were grouped
together.
#Get genera with mean realtive abundance >0.0001 across all samples
ps_rel_genus_sum <- ps_rel_melt%>% group_by(Rank7) %>% dplyr::summarise(Aver = mean(Abundance))
ps_rel_genus_sub <- ps_rel_genus_sum[which(ps_rel_genus_sum$Aver > 0.0001),]
names_ps_rel_genus <- ps_rel_genus_sub$Rank7
names_ps_rel_genus
# Replace genera with <0.001 abundance with "NA"
ps_rel_melt$Rank7[ps_rel_melt$Rank7 != "Abiotrophia" &
ps_rel_melt$Rank7 != "Aerococcus" &
ps_rel_melt$Rank7 != "Dialister" &
ps_rel_melt$Rank7 != "Granulicatella" &
ps_rel_melt$Rank7 != "Ignavibacterium" &
ps_rel_melt$Rank7 != "Lacticaseibacillus" &
ps_rel_melt$Rank7 != "Lacticaseibacillus" &
ps_rel_melt$Rank7 != "Lactiplantibacillus" &
ps_rel_melt$Rank7 != "Lactobacillus" &
ps_rel_melt$Rank7 != "Lancefieldella" &
ps_rel_melt$Rank7 != "Lentilactobacillus" &
ps_rel_melt$Rank7 != "Levilactobacillus" &
ps_rel_melt$Rank7 != "Limosilactobacillus" &
ps_rel_melt$Rank7 != "Megasphaera" &
ps_rel_melt$Rank7 != "Moryella" &
ps_rel_melt$Rank7 != "Shuttleworthia" &
ps_rel_melt$Rank7 != "Solobacterium" &
ps_rel_melt$Rank7 != "Staphylococcus" &
ps_rel_melt$Rank7 != "Streptococcus" &
ps_rel_melt$Rank7 != "Veillonella"] <- NA
#replace NA with "Rel. Abund.<0.0001"
ps_rel_melt[is.na(ps_rel_melt)]<-"Rel. Abund.<0.0001"
#Genera plot
taxaplot_ps_rel_genus = ggplot(ps_rel_melt
, aes(x = treatment, y=Abundance)) +
geom_bar(stat="identity", position="fill", aes(fill = Rank7)) +
scale_fill_manual(values=c("aquamarine4", "gold","lightpink", "firebrick","#DA5724","ivory4",
"orchid", "#CBD588", "#8569D5", "#D14285", "#652926","grey80",
"#5E738F","#D1A33D", "#8A7C64","lightgreen","aquamarine4",
"aquamarine2", "lightsalmon", "#CD9BCD")) +
theme_bw() +
ylab("Relative Abundance") + xlab("Treatment") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0))
taxaplot_ps_rel_genus <- taxaplot_ps_rel_genus + guides(fill=guide_legend(title="Genus"))
taxaplot_ps_rel_genus

ggsave("taxaplot_genus.tiff", dpi = 300, plot = taxaplot_ps_rel_genus, path = "./taxaplots/")
Species
Species with a relative abundance lower than 0.01 were grouped
together.
#Get species with mean realtive abundance >0.01 across all samples
ps_rel_species_sum <- ps_rel_melt%>% group_by(Rank9) %>% dplyr::summarise(Aver = mean(Abundance))
ps_rel_species_sub <- ps_rel_species_sum[which(ps_rel_species_sum$Aver > 0.01),]
names_ps_rel_species <- ps_rel_species_sub$Rank9
names_ps_rel_species
# Replace genera with <0.001 abundance with "NA"
# Replace genera with <0.001 abundance with "NA"
ps_rel_melt$Rank9[ps_rel_melt$Rank9 != "Lactobacillus crispatus" &
ps_rel_melt$Rank9 != "Lactobacillus jensenii" &
ps_rel_melt$Rank9 != "Limosilactobacillus fermentum" &
ps_rel_melt$Rank9 != "Limosilactobacillus vaginalis" &
ps_rel_melt$Rank9 != "Megasphaera micronuciformis" &
ps_rel_melt$Rank9 != "Streptococcus anginosus" &
ps_rel_melt$Rank9 != "Streptococcus mutans" &
ps_rel_melt$Rank9 != "Streptococcus salivarius" &
ps_rel_melt$Rank9 != "Streptococcus vestibularis" &
ps_rel_melt$Rank9 != "Veillonella atypica" &
ps_rel_melt$Rank9 != "Veillonella dispar" &
ps_rel_melt$Rank9 != "Veillonella genomosp. P1 oral clone MB5_P17" &
ps_rel_melt$Rank9 != "Veillonella sp. oral taxon 158"] <- NA
#replace NA with "Rel. Abund.<0.01"
ps_rel_melt[is.na(ps_rel_melt)]<-"Rel. Abund.<0.01"
#Species plot
taxaplot_ps_rel_species = ggplot(ps_rel_melt
, aes(x = treatment, y=Abundance)) +
geom_bar(stat="identity", position="fill", aes(fill = Rank9)) +
scale_fill_manual(values=c("aquamarine4", "gold","lightpink", "firebrick","#DA5724","ivory4",
"orchid", "#CBD588", "#8569D5", "#D14285", "#652926","grey80",
"#5E738F", "#D1A33D")) +
theme_bw() +
ylab("Relative Abundance") + xlab("Treatment") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0))
taxaplot_ps_rel_species <- taxaplot_ps_rel_species + guides(fill=guide_legend(title="Species"))
taxaplot_ps_rel_species

ggsave("taxaplot_species.tiff", dpi = 300, plot = taxaplot_ps_rel_species, path = "./taxaplots/")
Relative abundance top 10 taxa bar plots per sample
Plots were made at the phylum, genus, and species level, comparing
across all samples.
Images of each plot can be found in the stats_analysis/taxaplots/
directory.
Top 10 Phyla
# transform to relative abundance
ps_rel <- transform(ps_object, "compositional")
#Top 10 PHYLA
#Get phylum level
ps_phylum <- tax_glom(ps_rel, taxrank= "Rank3")
#Get top 10 phylum
phylum_top10 <- names(sort(taxa_sums(ps_phylum), decreasing=TRUE))[1:10]
ps_phylum_top10 <- prune_taxa(phylum_top10, ps_phylum)
# melt the data into a table
ps_phylum_melt<- ps_phylum_top10 %>%
psmelt()
# Plot top 10 phylum by sample
taxaplot_ps_top10_phylum = ggplot(ps_phylum_melt
, aes(x = sample, y=Abundance)) +
geom_bar(stat="identity", position="fill", aes(fill = Rank3)) +
scale_fill_manual(values=c("aquamarine4", "gold","lightpink", "firebrick","#DA5724","ivory4",
"orchid", "#CBD588", "#8569D5", "#D14285")) +
theme_bw() +
ylab("Relative Abundance") + xlab("Sample") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0)) +
theme(legend.title = element_text(size=9), legend.text = element_text(size=7))
taxaplot_ps_top10_phylum <- taxaplot_ps_top10_phylum + guides(fill=guide_legend(title="Top 10 Phyla"))
taxaplot_ps_top10_phylum

ggsave("taxaplot_top10_phylum.tiff", dpi = 300, width = 18, height = 8, units = "in", plot = taxaplot_ps_top10_phylum, path = "./taxaplots/")
Top 10 Genera
#Top 10 GENERA
#Get genus level
ps_genus <- tax_glom(ps_rel, taxrank= "Rank7")
#Get top 10 genera
genus_top10 <- names(sort(taxa_sums(ps_genus), decreasing=TRUE))[1:10]
ps_genus_top10 <- prune_taxa(genus_top10, ps_genus)
# melt the data into a table
ps_genus_melt<- ps_genus_top10 %>%
psmelt()
#head(ps_genus_melt)
# Plot top 10 phylum by sample
taxaplot_ps_top10_genus = ggplot(ps_genus_melt
, aes(x = sample, y=Abundance)) +
geom_bar(stat="identity", position="fill", aes(fill = Rank7)) +
scale_fill_manual(values=c("aquamarine4", "gold3","lightpink", "firebrick","#DA5724","ivory4",
"orchid", "#CBD588", "#8569D5", "#D14285")) +
theme_bw() +
ylab("Relative Abundance") + xlab("Sample") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0)) +
theme(legend.title = element_text(size=9), legend.text = element_text(size=7))
taxaplot_ps_top10_genus <- taxaplot_ps_top10_genus + guides(fill=guide_legend(title="Top 10 Genera"))
taxaplot_ps_top10_genus

ggsave("taxaplot_top10_genus.tiff", dpi = 300, width = 18, height = 8, units = "in", plot = taxaplot_ps_top10_genus, path = "./taxaplots/")
Top 10 Species
#Top 10 SPECIES
#Get species level
ps_species <- tax_glom(ps_rel, taxrank= "Rank9")
#Get top 10 genera
species_top10 <- names(sort(taxa_sums(ps_species), decreasing=TRUE))[1:10]
ps_species_top10 <- prune_taxa(species_top10, ps_species)
# melt the data into a table
ps_species_melt<- ps_species_top10 %>%
psmelt()
#head(ps_species_melt)
# Plot top 10 phylum by sample
taxaplot_ps_top10_species = ggplot(ps_species_melt
, aes(x = sample, y=Abundance)) +
geom_bar(stat="identity", position="fill", aes(fill = Rank9)) +
scale_fill_manual(values=c("aquamarine4", "gold3","lightpink", "firebrick","#DA5724","ivory4",
"orchid", "#CBD588", "#8569D5", "#D14285")) +
theme_bw() +
ylab("Relative Abundance") + xlab("Sample") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0)) +
theme(legend.title = element_text(size=9), legend.text = element_text(size=7))
taxaplot_ps_top10_species <- taxaplot_ps_top10_species + guides(fill=guide_legend(title="Top 10 Species"))
taxaplot_ps_top10_species

ggsave("taxaplot_top10_species.tiff", dpi = 300, width = 18, height = 8, units = "in", plot = taxaplot_ps_top10_species, path = "./taxaplots/")
LS0tCnRpdGxlOiAiMTZTIE9OVCBTZXF1ZW5jZSBhbmQgU3RhdGlzdGljYWwgQW5hbHlzaXMiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBkZl9wcmludDogcGFnZWQKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBGQUxTRSkKYGBgCiMjIE9OVCAxNlMgU2VxdWVuY2luZyBGaWxlcwpSYXcgZmFzdDUgZmlsZXMgZnJvbSBlYWNoIE94Zm9yZCBOYW5vcG9yZSAoT05UKSBzZXF1ZW5jaW5nIGJhdGNoIGNhbiBiZSBmb3VuZCB3aXRoaW4gdGhlIGRpcmVjdG9yeSBuYW1lZDogcmF3X2Zhc3Q1X2ZpbGVzLwoKfCBBIHRvdGFsIG9mIDggc2VxdWVuY2luZyBiYXRjaGVzIHdlcmUgcnVuLiBFYWNoIGJhdGNoIGluY2x1ZGVzIDI0IHNhbXBsZXMgZnJvbSB0aGUgZm9sbG93aW5nIHRyZWF0bWVudCBhbmQgZG9ub3IgaWRzOgoKfCAgICAgICAxLiBVVDEsIFVUMiwgVVQzCgp8ICAgICAgIDIuIFVUNCwgVVQ1LCBVVDYKCnwgICAgICAgMy4gUExBMSwgUExBMiwgUExBMwoKfCAgICAgICA0LiBQTEE0LCBQTEE1LCBQTEE2ICpOT1RFOiBUaGVzZSBzYW1wbGVzIGhhZCB0byBiZSByZS1ydW4gc28gdGhleSByZXByZXNlbnQgdHdvIHNlcGFyYXRlIHNlcXVlbmNpbmcgcnVucwoKfCAgICAgICA1LiBUMS0xLCBUMS0yLCBUMS0zCgp8ICAgICAgIDYuIFQxLTQsIFQxLTUsIFQxLTYKCnwgICAgICAgNy4gVDItMSwgVDItMiwgVDItMwoKfCAgICAgICA4LiBUMi00LCBUMi01LCBUMi02Cgp8IFNvIGZvciBleGFtcGxlLCB0aGUgcmF3IGZhc3Q1IGZpbGVzIG9mIHNhbXBsZXMgd2l0aGluIFVUMSwgVVQyLCBVVDMgd291bGQgYmUgaW46IHJhd19mYXN0NV9maWxlcy9VVDFfVVQyX1VUM19mYXN0NXMvCgojIyBPTlQgMTZTIFNlcXVlbmNlIFFDIFBpcGVsaW5lCgp8IEFmdGVyIE9OVCBzZXF1ZW5jaW5nIHRoZSBmb2xsb3dpbmcgcGlwZWxpbmUgd2FzIHVzZWQgdG8gZGVtdWx0aXBsZXggYW5kIHF1YWxpdHkgZmlsdGVyIHJlYWRzOgoKfCAxLiBCYXNlY2FsbCB3aXRoIERvcmFkbyBWIDAuNC4xIGh0dHBzOi8vZ2l0aHViLmNvbS9uYW5vcG9yZXRlY2gvZG9yYWRvCgp8IDIuIERlbXVsdGlwbGV4IHdpdGggR3VwcHkgViA2LjQuNiAoZ3VwcHlfYmFyY29kZXI6IGh0dHBzOi8vY29tbXVuaXR5Lm5hbm9wb3JldGVjaC5jb20vZG9jcy9wcmVwYXJlL2xpYnJhcnlfcHJlcF9wcm90b2NvbHMvR3VwcHktcHJvdG9jb2wvdi9ncGJfMjAwM192MV9yZXZheF8xNGRlYzIwMTgvYmFyY29kaW5nLWRlbXVsdGlwbGV4aW5nKSAKCnwgMy4gUmVhZCBxdWFsaXR5IGZpbHRlcmluZyBhbmQgdHJpbW1pbmcgd2l0aCBDaG9wcGVyIFYgMC42LjAgaHR0cHM6Ly9naXRodWIuY29tL3dkZWNvc3Rlci9jaG9wcGVyIAp8ICAgIFRyaW1tZWQgZmFzdHEgZmlsZXMgY2FuIGJlIGZvdW5kIGluIHRoZSBkaXJlY3RvcnkgbmFtZWQ6IHRyaW1tZWRfZmFzdHFzCgp8ICAgICAgIENob3BwZXIgcGFyYW1ldGVycyB1c2VkOgoKfCAgICAgICAgICAg4oCiCU1pbiBxIHNjb3JlOiAxMAoKfCAgICAgICAgICAg4oCiCU1pbiBsZW5ndGg6IDEsMDAwIGJwIAoKfCAgICAgICAgICAg4oCiCUhlYWQgY3JvcDogNTAKCnwgICAgICAgICAgIOKAoglNYXggbGVuZ3RoOiAxNjkwCgp8IDQuIE11bHRpcWMgcmVzdWx0cyBzdW1tYXJ5IHVzaW5nIGZhc3RwIHFjIFYgMC4yMC4xIAp8ICAgIE11bHRpcWMgcmVzdWx0cyBmb3IgZWFjaCBzZXF1ZW5jaW5nIGJhdGNoIGNhbiBiZSBmb3VuZCBpbiB0aGUgZGlyZWN0b3J5IG5hbWVkOiBtdWx0aXFjCgp8IEZ1bGwgcGlwZWxpbmUgd2l0aCBjb2RlIGlzIGF2YWlsYWJsZSBhdDogaHR0cHM6Ly9naXRodWIuY29tL01lc3N5YXN6QS9PTlRfZGVtdXggCgojIyMgVGF4b25vbWljIENsYXNzaWZpY2F0aW9uClF1YWxpdHkgZmlsdGVyZWQgYW5kIHRyaW1tZWQgcmVhZHMgd2VyZSB0aGVuIGFsaWduZWQgdG8gdGhlIEhPTUQgZGF0YWJhc2UgYW5kIGJpb20gZmlsZXMgd2VyZSBjcmVhdGVkIGZvciBpbXBvcnQgaW50byBwaHlsb3NlcS4KCm8JRmlyc3QsIGJ1aWx0IGEgS3Jha2VuMiBkYXRhYmFzZSBvZiB0aGUgMTZTIEhPTUQgc2VxdWVuY2VzIChodHRwczovL3d3dy5ob21kLm9yZy9mdHAvMTZTX3JSTkFfcmVmc2VxL0hPTURfMTZTX3JSTkFfUmVmU2VxL2N1cnJlbnQvSE9NRF8xNlNfclJOQV9SZWZTZXFfVjE1LjIzLmZhc3RhKSAKCnwgMS4gVGF4b25vbWljYWxseSBjbGFzc2lmaWVkIHJlYWRzIHZpYSBLcmFrZW4yIHRvIHRoZSBidWlsdCBIT01EIDE2UyBkYXRhYmFzZQoKfCAyLiBFc3RpbWF0ZWQgYWJ1bmRhbmNlIG9mIHRheGEgdmlhIEJyYWNrZW4gaHR0cHM6Ly9jY2Iuamh1LmVkdS9zb2Z0d2FyZS9icmFja2VuLyAKfCAgICAgICBLcm9uYSBncmFwaHMgb2YgdGhlIEJyYWNrZW4gYWJ1bmRhbmNlIGVzdGltYXRlcyBmb3IgZWFjaCBzYW1wbGUgY2FuIGJlIGZvdW5kIGluIHRoZSBkaXJlY3RvcnkgbmFtZWQ6IGtyb25hX2JyYWNrZW4KCnwgMy4gRXhwb3J0ZWQgQnJhY2tlbiByZXN1bHRzIGFzIGEgYmlvbSBmaWxlIGZvciBpbXBvcnQgaW50byBwaGx5b3NlcSAodmlhIHRheHBhc3RhIFYgMC42LjEgaHR0cHM6Ly90YXhwYXN0YS5yZWFkdGhlZG9jcy5pby9lbi9sYXRlc3QvKSAKCnwgRnVsbCBwaXBlbGluZSB3aXRoIGNvZGUgZm9yIHRoZXNlIDMgc3RlcHMgaXMgYXZhaWxhYmxlIGF0OiBodHRwczovL2dpdGh1Yi5jb20vTWVzc3lhc3pBL2JyYWNrZW5fdGF4cGFzdGEgCgojIyBTdGF0aXN0aWNhbCBBbmFseXNpcwpEaXZlcnNpdHksIGRpZmZlcmVudGlhbCBhYnVuZGFuY2UsIGFuZCByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgdGF4YSB3ZXJlIGFuYWx5emVkIHZpYSBQaHlsb3NlcSBhbmQgc3RhdGlzdGljYWwgdGVzdHMgd2VyZSBydW4gYmV0d2VlbiB0aGUgNCB0cmVhdG1lbnRzLiAKClRoZSBiaW9tIGZpbGUgYW5kIG1ldGFkYXRhIHRhYmxlIGltcG9ydGVkIGludG8gcGh5bG9zZXEgY2FuIGJlIGZvdW5kIGluIHRoZSBkaXJlY3RvcnkgbmFtZWQ6IHN0YXRzX2FuYWx5c2lzCgpSZXN1bHRzIGluY2x1ZGU6Cgp8IG8gQWxwaGEgZGl2ZXJzaXR5IG1ldHJpY3MgLSBPYnNlcnZlZCwgU2hhbm5vbiwgU2ltcHNvbiAoY3N2IHRhYmxlcyBpbiBzdGF0c19hbmFseXNpcyBkaXJlY3RvcnkpCgp8IG8JQWxwaGEgZGl2ZXJzaXR5IHN0YXRpc3RpY2FsIHRlc3RzIChyZXN1bHRzIGJlbG93KQoKfCBvCUFscGhhIGRpdmVyc2l0eSBib3hwbG90cyAodGlmZiBpbWFnZXMgaW4gc3RhdHNfYW5hbHlzaXMvYWxwaGFfZGl2ZXJzaXR5X3Bsb3RzIGRpcmVjdG9yeSkKCnwgICAgICAg4oCiCSpOT1RFOiBPYnNlcnZlZCByaWNobmVzcyB3YXMgcnVuIG9uIHJhdyBhbmQgbm9ybWFsaXplZCBkYXRhLiBSYXJlZmFjdGlvbiB0byBsb3dlc3QgcmVhZCBudW1iZXIgd2FzIHVzZWQgYXMgbm9ybWFsaXphdGlvbi4KfCAgICAgICBUaGlzIHdhcyBpbmNsdWRlZCBmb3IgY29tcGFyYXRpdmUgcHVycG9zZXMuIE90aGVyIG5vcm1hbGl6YXRpb24gbWV0aG9kcyBjYW4gYWxzbyBiZSBydW4gaWYgcmVxdWVzdGVkLgoKfCBvCVBhaXJ3aXNlIGRpZmZlcmVudGlhbCBhYnVuZGFuY2UgdGVzdCB2aWEgRGVTZXEyIChjc3YgdGFibGUgcmVzdWx0cyBpbiBzdGF0c19hbmFseXNpcy9ERVNFUTIgZGlyZWN0b3J5KQoKfCAgICAgICDigKIJVm9sY2FubyBwbG90ICh0aWZmIGltYWdlIGluIHN0YXRzX2FuYWx5c2lzL0RFU0VRMiBkaXJlY3RvcnkpCgp8ICAgICAgIOKAogkqTk9URTogQW5vdGhlciBkaWZmZXJlbnRpYWwgYWJ1bmRhbmNlIG1ldGhvZCBmb3IgbWljcm9iaW9tZSBkYXRhIChBTkNPTS1CQwp8ICAgICAgIGh0dHBzOi8vd3d3LmJpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvQU5DT01CQy5odG1sICkgY2FuIGJlIHJ1biBpZiByZXF1ZXN0ZWQuCgoKfCBvCUJldGEgZGl2ZXJzaXR5IHN0YXRpc3RpY2FsIHRlc3RzIC0gQnJheS1DdXJ0aXMsIEV1Y2xpZGVhbiBkaXN0YW5jZXMKCnwgICAgICAg4oCiCSpOT1RFOiBNZXRob2RzIGZvciBub3JtYWxpemluZyBiZXRhIGRpdmVyc2l0eSBtZXRyaWNzIChpLmUuIGNhbGN1bGF0aW5nIEFpdGNoaXNvbiBkaXN0YW5jZSB2aWEgdGhlIGRlaWNvZGUgcGFja2FnZSBpbiBRaWltZTIKfCAgICAgICBodHRwczovL2xpYnJhcnkucWlpbWUyLm9yZy9wbHVnaW5zL2RlaWNvZGUvMTkvKSBjYW4gYmUgcnVuIGlmIHJlcXVlc3RlZC4gCgp8IG8JQmV0YSBkaXZlcnNpdHkgcGxvdHMgKHRpZmYgaW1hZ2VzIGluIHN0YXRzX2FuYWx5c2lzL2JldGFfZGl2ZXJzaXR5X3Bsb3RzIGRpcmVjdG9yeSkKCnwgbwlSZWxhdGl2ZSBhYnVuZGFuY2UgdGF4YSBwbG90cyAodGlmZiBpbWFnZXMgY2FuIGJlIGZvdW5kIGluIHN0YXRzX2FuYWx5c2lzL3RheGFwbG90cyBkaXJlY3RvcnkpCmBgYHtyIExpYnJhcmllcywgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojTGlicmFyaWVzIHdlIHdpbGwgdXNlCmxpYnJhcnkoIkRFU2VxMiIpCmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KEJpb3N0cmluZ3MpCmxpYnJhcnkoInBoeWxvc2VxIikKbGlicmFyeSgibWljcm9iaW9tZSIpCmxpYnJhcnkoImdndGhlbWVzIikKbGlicmFyeShnZ25ldHdvcmspCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeSgidmVnYW4iKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKCiNDcmVhdGUgYSBmZXcgb3V0cHV0IGRpcmVjdG9yaWVzIHRoYXQgd2lsbCBob2xkIHRoZSBvdXRwdXQgZmlsZXMuIApkaXIuY3JlYXRlKCcuL0RFU0VRMicpCmRpci5jcmVhdGUoJy4vQU5DT00nKQpgYGAKCmBgYHtyIGRhdGFfbG9hZDEsIHdhcm5pbmc9RkFMU0V9CiMgTG9hZCBkYXRhIGFuZCBhZGQgbWV0YWRhdGEKcHNfb2JqZWN0IDwtIGltcG9ydF9iaW9tKCIuL0hPTURfYmlvbV9tZXJnZS5iaW9tIikKCiNpbXBvcnQgbWVkYXRhIGFuZCBhZGQgdG8gcGh5bG9zZXEgb2JqZWN0Cm1ldGFkYXRhIDwtIHJlYWQuY3N2KCIuL21ldGFkYXRhLmNzdiIsIHJvdy5uYW1lcyA9IDEpCm1ldGFkYXRhID0gc2FtcGxlX2RhdGEoZGF0YS5mcmFtZShtZXRhZGF0YSkpCnNhbXBsZV9kYXRhKHBzX29iamVjdCkgPC0gbWV0YWRhdGEKYGBgCiMjIFN0YXRpc3RpY2FsIEFuYWx5c2lzIFJlc3VsdHMKCiMjIyBUb3RhbCBudW1iZXIgb2YgdGF4YQpUaGUgdG90YWwgbnVtYmVyIG9mIHRheG9ub21pY2FsbHkgaWRlbnRpZmllZCBBU1ZzIGFjcm9zcyBhbGwgc2FtcGxlcwpgYGB7ciBkYXRhX2xvYWQyLCB3YXJuaW5nPUZBTFNFfQojQ2hlY2sgc2FtcGxlIG51bWJlcnMKbnRheGEocHNfb2JqZWN0KSAjVG90YWwgdGF4YQpgYGAKIyMjIE51bWJlciBvZiB0YXhvbm9taWNhbGx5IGNsYXNzaWZpZWQgcmVhZHMgcGVyIHNhbXBsZQpTYW1wbGVzIHdpbGwgaGF2ZSB2YXJ5aW5nIG51bWJlcnMgb2YgdGF4b25vbWljYWxseSBjbGFzc2lmaWVkIHJlYWRzIGR1ZSB0byBkaWZmZXJlbnQgc2FtcGxpbmcgZGVwdGhzIGR1cmluZyBzZXF1ZW5jaW5nLiAKYGBge3IgZGF0YV9sb2FkMywgd2FybmluZz1GQUxTRX0KI0NoZWNrIHNhbXBsZSBudW1iZXJzCnNhbXBsZV9zdW1zKHBzX29iamVjdCkgI1JlYWRzIHBlciBzYW1wbGUKYGBgCiMjIEFscGhhIERpdmVyc2l0eQpNZWFzdXJpbmcgc3BlY2llcyBkaXZlcnNpdHkgd2l0aGluIGVhY2ggc2FtcGxlLgpgYGB7ciBmdW5jdGlvbnN9CiNGdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIG1lYW4gYW5kIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIGVhY2ggZ3JvdXAuCiNkYXRhIDogYSBkYXRhIGZyYW1lCiN2YXJuYW1lIDogdGhlIG5hbWUgb2YgYSBjb2x1bW4gY29udGFpbmluZyB0aGUgdmFyaWFibGUgdG8gYmUgc3VtbWFyaXplZAojZ3JvdXBuYW1lcyA6IHZlY3RvciBvZiBjb2x1bW4gbmFtZXMgdG8gYmUgdXNlZCBhcyBncm91cGluZyB2YXJpYWJsZXMKCiMgQ2FsY3VsYXRlIHN0YW5kYXJkIGVycm9yCnNkZXJyIDwtIGZ1bmN0aW9uKHgpIHtzZCh4KS9zcXJ0KGxlbmd0aCh4KSl9CgpkYXRhX3N1bW1hcnkgPC0gZnVuY3Rpb24oZGF0YSwgdmFybmFtZSwgZ3JvdXBuYW1lcyl7CiAgcmVxdWlyZShwbHlyKQogIHN1bW1hcnlfZnVuYyA8LSBmdW5jdGlvbih4LCBjb2wpewogICAgYyhtZWFuID0gbWVhbih4W1tjb2xdXSwgbmEucm09VFJVRSksCiAgICAgIHNkID0gc2RlcnIoeFtbY29sXV0pLCBuYS5ybT1UUlVFKQogIH0KICBkYXRhX3N1bTwtZGRwbHkoZGF0YSwgZ3JvdXBuYW1lcywgLmZ1bj1zdW1tYXJ5X2Z1bmMsCiAgICAgICAgICAgICAgICAgIHZhcm5hbWUpCiAgZGF0YV9zdW0gPC0gcmVuYW1lKGRhdGFfc3VtLCBjKCJtZWFuIiA9IHZhcm5hbWUpKQogIHJldHVybihkYXRhX3N1bSkKfQpgYGAKCiMjIyBEYXRhIHRhYmxlIHdpdGggYWxwaGEgZGl2ZXJzaXR5IG1ldHJpY3M6IE9ic2VydmVkLCBTaGFubm9uLCBTaW1wc29uCiMjIyMgRXhhbXBsZSBvZiBkYXRhIHRhYmxlIHN0cnVjdHVyZSAoZnVsbCB0YWJsZSBzYXZlZCBhcyBjc3YpClRocmVlIGFscGhhIGRpdmVyc2l0eSBtZXRyaWNzIGFyZSBjYWxjdWxhdGVkIGZvciBlYWNoIHNhbXBsZS4KVGhlIGZ1bGwgdGFibGUgKHBlcl9zYW1wbGVfYWRfZGF0YWZyYW1lLmNzdikgY2FuIGJlIGZvdW5kIGluIHRoZSBkaXJlY3RvcnkgbmFtZWQ6IHN0YXRzX2FuYWx5c2lzCmBgYHtyIGRhdGFfdGFibGUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0KYWxwaGFfZGl2IDwtIGNiaW5kKGVzdGltYXRlX3JpY2huZXNzKHBzX29iamVjdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmVzID0gYygnT2JzZXJ2ZWQnLCAnU2hhbm5vbicsICdTaW1wc29uJykpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfZGF0YShwc19vYmplY3QpKQpjb2xuYW1lcyhhbHBoYV9kaXYpIDwtIGMoJ09ic2VydmVkJywgJ1NoYW5ub24nLCAnU2ltcHNvbicpCmFscGhhX2RpdiRMYWJlbHMgPC0gcm93bmFtZXMoYWxwaGFfZGl2KQphZF9kZiA8LSBhbHBoYV9kaXZbLGMoJ09ic2VydmVkJywgJ1NoYW5ub24nLCAnU2ltcHNvbicpXQphZF9kZiA8LSBjYmluZChhZF9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEocHNfb2JqZWN0KVssIGMoJ3NhbXBsZScsICdncm91cCcsICdkb25vcicsICd0cmVhdG1lbnQnKV0pCmNvbG5hbWVzKGFkX2RmKSA8LSBjKCdPYnNlcnZlZCcsICdTaGFubm9uJywgJ1NpbXBzb24nLCAnc2FtcGxlJywgJ2dyb3VwJywgJ2Rvbm9yJywgJ3RyZWF0bWVudCcpCmhlYWQoYWRfZGYpCndyaXRlLmNzdihhZF9kZiwgIi4vcGVyX3NhbXBsZV9hZF9kYXRhZnJhbWUuY3N2IikKYGBgCiMjIyBEYXRhIFN1bW1hcnkgc3RhdGlzdGljczogT2JzZXJ2ZWQsIFNoYW5ub24sIFNpbXBzb24KIyMjIyBTdW1tYXJ5IGZvciBlYWNoIHRyZWF0bWVudApUaGUgYXZlcmFnZSBvZiBlYWNoIGFscGhhIGRpdmVyc2l0eSBtZXRyaWMgZm9yIGFsbCBzYW1wbGVzIHdpdGhpbiBhIHRyZWF0bWVudC4gCmBgYHtyIHN1bW1hcnlfc3RhdHMsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBPYnNlcnZlZApkYXRhX3N1bW1hcnkoYWRfZGYsIHZhcm5hbWUgPSAiT2JzZXJ2ZWQiLCBncm91cG5hbWVzID0gYygidHJlYXRtZW50IikpCiNkYXRhX3N1bW1hcnkoYWRfZGYsIHZhcm5hbWUgPSAiT2JzZXJ2ZWQiLCBncm91cG5hbWVzID0gYygic2FtcGxlIikpCiNkYXRhX3N1bW1hcnkoYWRfZGYsIHZhcm5hbWUgPSAiT2JzZXJ2ZWQiLCBncm91cG5hbWVzID0gYygiZG9ub3IiKSkKCiMgU2hhbm5vbgpkYXRhX3N1bW1hcnkoYWRfZGYsIHZhcm5hbWUgPSAiU2hhbm5vbiIsIGdyb3VwbmFtZXMgPSBjKCJ0cmVhdG1lbnQiKSkKI2RhdGFfc3VtbWFyeShhZF9kZiwgdmFybmFtZSA9ICJTaGFubm9uIiwgZ3JvdXBuYW1lcyA9IGMoInNhbXBsZSIpKQojZGF0YV9zdW1tYXJ5KGFkX2RmLCB2YXJuYW1lID0gIlNoYW5ub24iLCBncm91cG5hbWVzID0gYygiZG9ub3IiKSkKCiMgU2ltcHNvbgpkYXRhX3N1bW1hcnkoYWRfZGYsIHZhcm5hbWUgPSAiU2ltcHNvbiIsIGdyb3VwbmFtZXMgPSBjKCJ0cmVhdG1lbnQiKSkKI2RhdGFfc3VtbWFyeShhZF9kZiwgdmFybmFtZSA9ICJTaW1wc29uIiwgZ3JvdXBuYW1lcyA9IGMoInNhbXBsZSIpKQojZGF0YV9zdW1tYXJ5KGFkX2RmLCB2YXJuYW1lID0gIlNpbXBzb24iLCBncm91cG5hbWVzID0gYygiZG9ub3IiKSkKYGBgCiMjIyBBbHBoYSBkaXZlcnNpdHkgc3RhdGlzdGljYWwgdGVzdHMgZm9yIHNpZ25pZmljYW5jZQojIyMjIEtydXNrYWwgV2FsbGlzIGFuZCBQYWlyd2lzZSBXaWxjb3hvbiB0ZXN0cwpLcnVza2FsLVdhbGxpcyBSYW5rIFN1bSBUZXN0IGZvciBhIGNhdGVnb3J5ICh0cmVhdG1lbnQpIG9uIGVhY2ggQWxwaGEgRGl2ZXJzaXR5IG1ldHJpYyBjYWxjdWxhdGVkLiBUaGlzIGlzIGEgbm9uLXBhcmFtZXRyaWMgbWV0aG9kIHdoaWNoIHJhbmtzIHRoZSBkYXRhIGFuZCB0ZXN0cyB3aGV0aGVyIHNhbXBsZXMgZnJvbSBlYWNoIGdyb3VwIGFuYWx5emVkIGNvbWUgZnJvbSB0aGUgc2FtZSBkaXN0cmlidXRpb24uIAoKUGFpcndpc2UgV2lsY294b24gUmFuayBTdW0gVGVzdCBiZXR3ZWVuIGdyb3VwcyB3aXRoaW4gYSBjYXRlZ29yeSAodHJlYXRtZW50KSBvbiBlYWNoIEFscGhhIERpdmVyc2l0eSBtZXRyaWMgY2FsY3VsYXRlZCBhbmQgY29ycmVjdGVkIGZvciBtdWx0aXBsZSB0ZXN0aW5nLiBUaGlzIG1ldGhvZHMgY29tcGFyZXMgdHdvIGluZGVwZW5kZW50IHNhbXBsZXMgZm9yIGFsbCBncm91cCBsZXZlbHMgYW5kIGluY2x1ZGVzIHRoZSBmYWxzZSBkaXNjb3ZlcnkgcmF0ZSAoRkRSKSBtdWx0aXBsZSB0ZXN0IGNvcnJlY3Rpb24uIFRoZSByZXN1bHRzIGJlbG93IGNvbWUgdXAgYXMgYSBtYXRyaXggZmlsbGVkIHdpdGggdGhlIHAtdmFsdWVzIGZvciBlYWNoIHRyZWF0bWVudCBjb21wYXJpc29uLgoKIyMjIyBPYnNlcnZlZCBSaWNobmVzcyAKVGVzdGluZyBBU1Yvc3BlY2llcyByaWNobmVzcyBiZXR3ZWVuIHRoZSA0IHRyZWF0bWVudHMuCmBgYHtyIG9ic2VydmVkX2FkLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjIyMgT2JzZXJ2ZWQKI0tydXNrYWwgV2FsbGlzIHRlc3RzCmtydXNrYWwudGVzdChPYnNlcnZlZCB+IHRyZWF0bWVudCwgZGF0YSA9IGFkX2RmKQoja3J1c2thbC50ZXN0KE9ic2VydmVkIH4gc2FtcGxlLCBkYXRhID0gYWRfZGYpCiNrcnVza2FsLnRlc3QoT2JzZXJ2ZWQgfiBkb25vciwgZGF0YSA9IGFkX2RmKQoKI1BhaXJ3aXNlIFdpbGNveG9uIFRlc3QKcGFpcndpc2Uud2lsY294LnRlc3QoYWRfZGYkT2JzZXJ2ZWQsIGFkX2RmJHRyZWF0bWVudCwgcC5hZGp1c3QubWV0aG9kID0gJ2ZkcicpCmBgYAojIyMjIFNoYW5ub24gRGl2ZXJzaXR5ClRlc3RpbmcgQVNWL3NwZWNpZXMgcmljaG5lc3MgYmV0d2VlbiB0aGUgNCB0cmVhdG1lbnRzIHdoaWxlIGFsc28gdGFraW5nIGludG8gYWNjb3VudCByZWxhdGl2ZSBhYnVuZGFuY2UgKGV2ZW5uZXNzKS4KYGBge3Igc2hhbm5vbl9hZCwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIyMjIFNoYW5ub24KI0tydXNrYWwgV2FsbGlzIHRlc3RzCmtydXNrYWwudGVzdChTaGFubm9uIH4gdHJlYXRtZW50LCBkYXRhID0gYWRfZGYpCiNrcnVza2FsLnRlc3QoU2hhbm5vbiB+IHNhbXBsZSwgZGF0YSA9IGFkX2RmKQoja3J1c2thbC50ZXN0KFNoYW5ub24gfiBkb25vciwgZGF0YSA9IGFkX2RmKQoKI1BhaXJ3aXNlIFdpbGNveG9uIFRlc3QKcGFpcndpc2Uud2lsY294LnRlc3QoYWRfZGYkU2hhbm5vbiwgYWRfZGYkdHJlYXRtZW50LCBwLmFkanVzdC5tZXRob2QgPSAnZmRyJykKYGBgCiMjIyMgU2ltcHNvbiBEaXZlcnNpdHkKVGVzdGluZyBBU1Yvc3BlY2llcyByaWNobmVzcyBiZXR3ZWVuIHRoZSA0IHRyZWF0bWVudHMgd2hpbGUgYWxzbyB0YWtpbmcgaW50byBhY2NvdW50IHJlbGF0aXZlIGFidW5kYW5jZSAoZXZlbm5lc3MpLiBTaW1wc29uIGRpdmVyc2l0eSBnaXZlcyBtb3JlIHdlaWdodCB0byBjb21tb24gb3IgZG9taW5hbnQgQVNWcyAocmFyZSBBU1ZzIHdpbGwgbm90IGFmZmVjdCBkaXZlcnNpdHkpLgpgYGB7ciBzaW1wc29uX2FkLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjIyMgU2ltcHNvbgojS3J1c2thbCBXYWxsaXMgdGVzdHMKa3J1c2thbC50ZXN0KFNpbXBzb24gfiB0cmVhdG1lbnQsIGRhdGEgPSBhZF9kZikKI2tydXNrYWwudGVzdChTaW1wc29uIH4gc2FtcGxlLCBkYXRhID0gYWRfZGYpCiNrcnVza2FsLnRlc3QoU2ltcHNvbiB+IGRvbm9yLCBkYXRhID0gYWRfZGYpCgojUGFpcndpc2UgV2lsY294b24gVGVzdApwYWlyd2lzZS53aWxjb3gudGVzdChhZF9kZiRTaW1wc29uLCBhZF9kZiR0cmVhdG1lbnQsIHAuYWRqdXN0Lm1ldGhvZCA9ICdmZHInKQpgYGAKCiMjIyBBbHBoYSBkaXZlcnNpdHkgYm94cGxvdHMKSW1hZ2VzIG9mIGVhY2ggcGxvdCBjYW4gYmUgZm91bmQgaW46IHN0YXRzX2FuYWx5c2lzL2FscGhhX2RpdmVyc2l0eV9wbG90cwpgYGB7ciBBRCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCByZXN1bHRzPSdoaWRlJywgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9N30KIyMjR3JvdXAgcGxvdHMKI09ic2VydmVkCm9ic19hZF9wbG90IDwtIGdncGxvdChhZF9kZiwgYWVzKHg9dHJlYXRtZW50LCB5PU9ic2VydmVkLCBjb2xvciA9IHRyZWF0bWVudCkpICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX3BvaW50KCkgKyB5bGFiKCdPYnNlcnZlZCBSaWNobmVzcycpICsgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTU0NTM1IiwgIiM3MDI5NjMiLCAiI0YyOEMyOCIsICIjMDg4RjhGIikpCgpvYnNfYWRfcGxvdAoKZ2dzYXZlKCJvYnNfYWRfcGxvdC50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gb2JzX2FkX3Bsb3QsIHBhdGggPSAiLi9hbHBoYV9kaXZlcnNpdHlfcGxvdHMvIikKCiNTaGFubm9uCnNoYW5fYWRfcGxvdCA8LSBnZ3Bsb3QoYWRfZGYsIGFlcyh4PXRyZWF0bWVudCwgeT1TaGFubm9uLCBjb2xvciA9IHRyZWF0bWVudCkpICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX3BvaW50KCkgKyB5bGFiKCdTaGFubm9uIERpdmVyc2l0eScpICsgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTU0NTM1IiwgIiM3MDI5NjMiLCAiI0YyOEMyOCIsICIjMDg4RjhGIikpCgpzaGFuX2FkX3Bsb3QKCmdnc2F2ZSgic2hhbl9hZF9wbG90LnRpZmYiLCBkcGkgPSAzMDAsIHBsb3QgPSBzaGFuX2FkX3Bsb3QsIHBhdGggPSAiLi9hbHBoYV9kaXZlcnNpdHlfcGxvdHMvIikKCiNTaW1wc29uCnNpbXBfYWRfcGxvdCA8LSBnZ3Bsb3QoYWRfZGYsIGFlcyh4PXRyZWF0bWVudCwgeT1TaW1wc29uLCBjb2xvciA9IHRyZWF0bWVudCkpICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX3BvaW50KCkgKyB5bGFiKCdTaW1wc29uIERpdmVyc2l0eScpICsgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTU0NTM1IiwgIiM3MDI5NjMiLCAiI0YyOEMyOCIsICIjMDg4RjhGIikpCgpzaW1wX2FkX3Bsb3QKCmdnc2F2ZSgic2ltcF9hZF9wbG90LnRpZmYiLCBkcGkgPSAzMDAsIHBsb3QgPSBzaW1wX2FkX3Bsb3QsIHBhdGggPSAiLi9hbHBoYV9kaXZlcnNpdHlfcGxvdHMvIikKYGBgCiMjIEFscGhhIERpdmVyc2l0eSBvbiBSYXJlZmllZCBEYXRhCiMjIyBOb3JtYWxpemUgT2JzZXJ2ZWQgUmljaG5lc3MgbWV0cmljIGJ5IHJhcmVmeWluZyB0byBsb3dlc3Qgc2FtcGxlIHN1bSBudW1iZXIKU2hhbm5vbiBhbmQgU2ltcHNvbiBkaXZlcnNpdHkgaW5kaWNlcyBhcmUgYWxyZWFkeSBub3JtYWxpemVkIGJ5IHJlbGF0aXZlIGFidW5kYW5jZS4gCgojIyMgUmFyZWZhY3Rpb24gcmVhZCBkZXB0aApPbmUgbWV0aG9kIG9mIG5vcm1hbGl6YXRpb24gaXMgdG8gcmFyZWZ5IGVhY2ggc2FtcGxlIHRvIHRoZSBtaW5pbXVtIHJlYWQgZGVwdGggZm91bmQgYWNyb3NzIGFsbCBzYW1wbGVzLiBUaGUgbWluaW11bSByZWFkIGRlcHRoIGZvciBhbGwgc2FtcGxlcyBpczogCmBgYHtyIHJhcmVfbnVtLCB3YXJuaW5nPUZBTFNFfQptaW4oc2FtcGxlX3N1bXMocHNfb2JqZWN0KSkgI01pbmltdW0gcmVhZHMgKHVzZWQgZm9yIHJhcmVmeWluZykKYGBgCiMjIyMgRXhhbXBsZSBvZiBkYXRhdGFibGUgc3RydWN0dXJlIGZvciByYXJlZmllZCBkYXRhIG9ic2VydmVkIHJpY2huZXNzIChmdWxsIHRhYmxlIHNhdmVkIGFzIGNzdikKT2JzZXJ2ZWQgcmljaG5lc3MgaXMgY2FsY3VsYXRlZCBmb3IgZWFjaCBzYW1wbGUgbm93IHJhcmVmaWVkIHRvIHRoZSBtaW5pbXVtIHJlYWQgZGVwdGguClRoZSBmdWxsIHRhYmxlIChyYXJlZmllZF9wZXJfc2FtcGxlX2FkX2RhdGFmcmFtZS5jc3YpIGNhbiBiZSBmb3VuZCBpbiB0aGUgZGlyZWN0b3J5IG5hbWVkOiBzdGF0c19hbmFseXNpcwpgYGB7ciBBRF9yYXJlZmllZCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KI1JhcmVmeSB0byBsb3dlc3Qgc2FtcGxlX3N1bXMKcmFyZV9udW0gPC0gbWluKHNhbXBsZV9zdW1zKHBzX29iamVjdCkpCnBzX3JhcmUgPC0gcmFyZWZ5X2V2ZW5fZGVwdGgocHNfb2JqZWN0LCBzYW1wbGUuc2l6ZSA9IHJhcmVfbnVtLCBybmdzZWVkID0gOTk5KQoKI0dldCBkYXRhdGFibGUgd2l0aCBPYnNlcnZlZCByaWNobmVzcyBmb3IgcmFyZWZpZWQgc2FtcGxlcwphbHBoYV9kaXZfcmFyZSA8LSBjYmluZChlc3RpbWF0ZV9yaWNobmVzcyhwc19yYXJlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZXMgPSBjKCdPYnNlcnZlZCcpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEocHNfcmFyZSkpCmNvbG5hbWVzKGFscGhhX2Rpdl9yYXJlKSA8LSBjKCdPYnNlcnZlZF9yYXJlJykKYWxwaGFfZGl2X3JhcmUkTGFiZWxzIDwtIHJvd25hbWVzKGFscGhhX2Rpdl9yYXJlKQphZF9kZl9yYXJlIDwtIGFscGhhX2Rpdl9yYXJlWyxjKCdPYnNlcnZlZF9yYXJlJyldCmFkX2RmX3JhcmUgPC0gY2JpbmQoYWRfZGZfcmFyZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEocHNfcmFyZSlbLCBjKCdzYW1wbGUnLCAnZ3JvdXAnLCAnZG9ub3InLCAndHJlYXRtZW50JyldKQpjb2xuYW1lcyhhZF9kZl9yYXJlKSA8LSBjKCdPYnNlcnZlZF9yYXJlJywgJ3NhbXBsZScsICdncm91cCcsICdkb25vcicsICd0cmVhdG1lbnQnKQpoZWFkKGFkX2RmX3JhcmUpCndyaXRlLmNzdihhZF9kZl9yYXJlLCAiLi9yYXJlZmllZF9wZXJfc2FtcGxlX2FkX2RhdGFmcmFtZS5jc3YiKQpgYGAKIyMjIyBEYXRhIHN1bW1hcnkgZm9yIHJhcmVmaWVkIGRhdGEgKG9ic2VydmVkIHJpY2huZXNzKQpUaGUgYXZlcmFnZSBvYnNlcnZlZCByaWNobmVzcyBmb3IgYWxsIHNhbXBsZXMgd2l0aGluIGEgdHJlYXRtZW50LiAKYGBge3IgYWRfcmFyZV9zdW1tYXJ5LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIE9ic2VydmVkIFJhcmVmaWVkIGRhdGEgc3VtbWFyeSBzdGF0cwpkYXRhX3N1bW1hcnkoYWRfZGZfcmFyZSwgdmFybmFtZSA9ICJPYnNlcnZlZF9yYXJlIiwgZ3JvdXBuYW1lcyA9IGMoInRyZWF0bWVudCIpKQojZGF0YV9zdW1tYXJ5KGFkX2RmX3JhcmUsIHZhcm5hbWUgPSAiT2JzZXJ2ZWRfcmFyZSIsIGdyb3VwbmFtZXMgPSBjKCJzYW1wbGUiKSkKI2RhdGFfc3VtbWFyeShhZF9kZl9yYXJlLCB2YXJuYW1lID0gIk9ic2VydmVkX3JhcmUiLCBncm91cG5hbWVzID0gYygiZG9ub3IiKSkKYGBgCgojIyMjIE9ic2VydmVkIHJpY2huZXNzIHN0YXRpc3RpY2FsIHRlc3RzIGZvciByYXJlZmllZCBkYXRhClRlc3RpbmcgQVNWL3NwZWNpZXMgcmljaG5lc3MgYmV0d2VlbiB0aGUgNCB0cmVhdG1lbnRzLgpgYGB7ciBhZF9yYXJlX3N0YXRzLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQoKIyMjIyBPYnNlcnZlZCBSYXJlZmllZAojS3J1c2thbCBXYWxsaXMgdGVzdHMKa3J1c2thbC50ZXN0KE9ic2VydmVkX3JhcmUgfiB0cmVhdG1lbnQsIGRhdGEgPSBhZF9kZl9yYXJlKQoja3J1c2thbC50ZXN0KE9ic2VydmVkX3JhcmUgfiBzYW1wbGUsIGRhdGEgPSBhZF9kZl9yYXJlKQoja3J1c2thbC50ZXN0KE9ic2VydmVkX3JhcmUgfiBkb25vciwgZGF0YSA9IGFkX2RmX3JhcmUpCgojUGFpcndpc2UgV2lsY294b24gVGVzdApwYWlyd2lzZS53aWxjb3gudGVzdChhZF9kZl9yYXJlJE9ic2VydmVkX3JhcmUsIGFkX2RmX3JhcmUkdHJlYXRtZW50LCBwLmFkanVzdC5tZXRob2QgPSAnZmRyJykKYGBgCiMjIyMgUmFyZWZpZWQgZGF0YSBvYnNlcnZlZCByaWNobmVzcyBib3hwbG90CkltYWdlcyBvZiB0aGUgcGxvdCBjYW4gYmUgZm91bmQgaW46IHN0YXRzX2FuYWx5c2lzL2FscGhhX2RpdmVyc2l0eV9wbG90cwpgYGB7ciBhZF9yYXJlX3Bsb3QsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgcmVzdWx0cz0naGlkZScsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTd9CiNQbG90czogT2JzZXJ2ZWQgUmFyZWZpZWQKb2JzX2FkX3Bsb3RfcmFyZSA8LSBnZ3Bsb3QoYWRfZGZfcmFyZSwgYWVzKHg9dHJlYXRtZW50LCB5PU9ic2VydmVkX3JhcmUsIGNvbG9yID0gdHJlYXRtZW50KSkgKyBnZW9tX2JveHBsb3QoKSArIGdlb21fcG9pbnQoKSArIHlsYWIoJ09ic2VydmVkIFJpY2huZXNzIFJhcmVmaWVkIERhdGEnKSArIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzk1NDUzNSIsICIjNzAyOTYzIiwgIiNGMjhDMjgiLCAiIzA4OEY4RiIpKQoKb2JzX2FkX3Bsb3RfcmFyZQoKZ2dzYXZlKCJyYXJlZmllZF9vYnNfYWRfcGxvdC50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gb2JzX2FkX3Bsb3RfcmFyZSwgcGF0aCA9ICIuL2FscGhhX2RpdmVyc2l0eV9wbG90cy8iKQpgYGAKCiMjIERpZmZlcmVudGlhbCBBYnVuZGFuY2UgQW5hbHlzaXMKIyMjIFBhaXJ3aXNlIGRpZmZlcmVudGlhbCBhYnVuZGFuY2UgdGVzdCBiZXR3ZWVuIHRyZWF0bWVudHMgdmlhIERFU2VxMgpUaGUgcGFja2FnZSBERVNlcTIgcHJvdmlkZXMgbWV0aG9kcyB0byB0ZXN0IGZvciBkaWZmZXJlbnRpYWwgYWJ1bmRhbmNlIGJ5IHVzZSBvZiBuZWdhdGl2ZSBiaW5vbWlhbCBnZW5lcmFsaXplZCBsaW5lYXIgbW9kZWxzLiBERVNlcTIgdXNlcyB0aGUgV2FsZCB0ZXN0IHRvIHRha2UgaW50byBhY2NvdW50IHRoZSBkaXNwZXJzaW9uIG1vZGVsIGRpc3RhbmNlIGFuZCBuZWdhdGl2ZSBiaW5vbWlhbCBkaXN0cmlidXRpb24gd2Ugc2VlIGluIHNlcXVlbmNpbmcgZGF0YS4gT3ZlcmFsbCB0aGlzIG1ldGhvZCBzdGF0aXN0aWNhbGx5IGluZmVycyBzeXN0ZW1hdGljIGNoYW5nZXMgYmV0d2VlbiBjb25kaXRpb25zLCBhcyBjb21wYXJlZCB0byB3aXRoaW4tY29uZGl0aW9uIHZhcmlhYmlsaXR5LiBJdCBlc3RpbWF0ZXMgZGlzcGVyc2lvbiBhbmQgbG9nYXJpdGhtaWMgZm9sZCBjaGFuZ2VzIHRvIHRlc3Qgd2hpY2ggc2VxdWVuY2VzL0FTVnMgYXJlIHNpZ25pZmljYW50bHkgY2hhbmdpbmcgd2l0aGluIHRoZSBleHBlcmltZW50YWwgZGVzaWduLiAKCkFkZGl0aW9uYWxseSwgYSBwLXZhbHVlIGNvcnJlY3Rpb24gaXMgYXBwbGllZCBmb3IgbXVsdGlwbGUgaHlwb3RoZXNpcyB0ZXN0aW5nLiBUcmFkaXRpb25hbGx5IHAgPCAwLjA1IGlzIGNvbnNpZGVyZWQgc2lnbmlmaWNhbnQgKDk1JSBjaGFuY2UgaXQgaXMgbm90IGJ5IHJhbmRvbSBjaGFuY2UpLCBidXQgd2hlbiB5b3UgYXJlIGxvb2tpbmcgYXQgdGhvdXNhbmRzIG9mIEFTVnMvc2VxdWVuY2VzLCB5b3UnbGwgc3RpbGwgZW5kIHVwIHdpdGggNSUgb2YgdGhlbSBzaWduaWZpY2FudCBvZmYgcHJlZGljdGVkIGNoYW5jZS4gT25lIG9mIHRoZSBiZXN0IGNvcnJlY3Rpb25zIHRvIHVzZSBjYWxsZWQgRmFsc2UtRGlzY292ZXJ5IFJhdGUgY29ycmVjdGlvbiAoRkRSKSwgd2hpY2ggaXMgdGhlIEJlbmphbWluaSBhbmQgSG9jaGJlcmcgbWV0aG9kLgoKSGVyZSB3ZSByYW4gREVTZXEyIHNwZWNpZnlpbmcgb25seSB0cmVhdG1lbnQgaW4gdGhlIGV4cGVyaW1lbnRhbCBkZXNpZ24uIExvZyBmb2xkIGNoYW5nZXMgYW5kIGFkanVzdGVkIHAtdmFsdXMgKHBhZGopIGZvciBhbGwgQVNWcyBhbmQgc2lnbmlmaWNhbnQgQVNWcyBoYXZlIGJlZW4gc2F2ZWQgYXMgY3N2IHRhYmxlcyBpbiB0aGUgc3RhdHNfYW5hbHlzaXMvREVTRVEyIGRpcmVjdG9yeSAobmFtZWQgZGRzX3Jlc3VsdF90YWJsZS5jc3YgYW5kIHNpZ19yZXN1bHRfdGFibGUuY3N2IHJlc3BlY3RpdmVseSkuCgpUaGUgYmVsb3cgcGxvdCBzaG93cyB0aGUgZml0dGVkIGN1cnZlIChyZWQgbGluZSkgdXNlZCB0byBjYWxjdWxhdGUgdGhlIGZpbmFsIGRpc3BlcnNpb24gZXN0aW1hdGVzIChibHVlIGRvdHMpIG9mIHRoZSBpbnB1dCBkYXRhIChibGFjayBkb3RzKS4gCmBgYHtyIERlc2VxLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD05fQojUGh5bG9zZXEgdG8gRGVzZXEyCnBzX2Rlc2VxID0gcGh5bG9zZXFfdG9fZGVzZXEyKHBzX29iamVjdCwgfnRyZWF0bWVudCkKCiNSdW4gRGVzZXEyCmRkcyA9IERFU2VxKHBzX2Rlc2VxLCB0ZXN0PSJXYWxkIiwgZml0VHlwZT0ibG9jYWwiKQpkZHNfcmVzdWx0IDwtIHJlc3VsdHMoZGRzKQpkZHNfcmVzdWx0X3RhYmxlIDwtIGNiaW5kKGFzKGRkc19yZXN1bHQsICJkYXRhLmZyYW1lIiksIGFzKHRheF90YWJsZShwc19vYmplY3QpW3Jvd25hbWVzKGRkc19yZXN1bHQpLCBdLCAibWF0cml4IikpCndyaXRlLmNzdihkZHNfcmVzdWx0X3RhYmxlLCAiLi9ERVNFUTIvZGRzX3Jlc3VsdF90YWJsZS5jc3YiKQoKI2NoZWNrIHNpZ25pZmljYW50IHJlc3VsdHMKZGRzX3NpZyA9IGRkc19yZXN1bHRbd2hpY2goZGRzX3Jlc3VsdCRwYWRqIDwgMC4wNSksIF0KZGRzX3NpZ190YWJsZSA9IGNiaW5kKGFzKGRkc19zaWcsICJkYXRhLmZyYW1lIiksIGFzKHRheF90YWJsZShwc19vYmplY3QpW3Jvd25hbWVzKGRkc19zaWcpLCBdLCAibWF0cml4IikpCmRpbShkZHNfc2lnX3RhYmxlKQp3cml0ZS5jc3YoZGRzX3NpZ190YWJsZSwgIi4vREVTRVEyL3NpZ19yZXN1bHRfdGFibGUuY3N2IikKCiNQZXJmb3JtIHRoZSB2YXJpYW5jZSBzdGFiaWxpemluZyB0cmFuc2Zvcm1hdGlvbiBvbiB0aGUgZGF0YSBhbmQgcHVsbCB0aGUgbm9ybWFsaXplZCBoaXQgY291bnQgbWF0cml4LiAKdnN0IDwtIHZhcmlhbmNlU3RhYmlsaXppbmdUcmFuc2Zvcm1hdGlvbihkZHMpCm1hdCA8LSBhc3NheSh2c3QpCgojSWYgeW91IGhhdmUgYSBiYXRjaCBkZXNpZ25lZCBpbiwgcmVncmVzcyB0aGUgYmF0Y2ggZWZmZWN0cy4gCiNtYXQgPC0gbGltbWE6OnJlbW92ZUJhdGNoRWZmZWN0KG1hdCwgdnN0JGJhdGNoKQojYXNzYXkodnN0KSA8LSBtYXQKCiNQbG90IHRoZSBvdmVyYWxsIGRpc3BlcnNpb24gb2YgdGhlIGV4cGVyaW1lbnQgdG8gZW5zdXJlIGl0IGFsaWducyB3aXRoIGV4cGVjdGF0aW9ucy4gCnBsb3REaXNwRXN0cyhkZHMpCmBgYAoKIyMjIFZvbGNhbm8gcGxvdDogRGVTZXEyIHJlc3VsdHMKVm9sY2FubyBwbG90cyBhcmUgYSBncmVhdCB3YXkgdG8gdmlzdWFsaXplIHRoZSBwYWlyd2lzZSBjb21wYXJpc29ucy4gRWFjaCBzaG93cyB0aGUgbG9nMiBmb2xkLWNoYW5nZSAobG9nMkZDKSBvbiB0aGUgeC1heGlzIGFuZCAtbG9nMTAocGFkaikgb24gdGhlIHktYXhpcy4gVGhpcyBzaG91bGQgdXN1YWxseSBsb29rIGFraW4gdG8gYSBQbGluaWFuIGVydXB0aW9uIChoZW5jZSB2b2xjYW5vIHBsb3QpLgoKSW1hZ2Ugb2YgdGhlIHZvbGNhbm8gcGxvdCBjYW4gYmUgZm91bmQgaW4gdGhlIHN0YXRzX2FuYWx5c2lzL0RFU0VRMi8gZGlyZWN0b3J5CmBgYHtyIFZvbGNhbm9lcywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCByZXN1bHRzPSdoaWRlJywgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OX0KcCA8LSBFbmhhbmNlZFZvbGNhbm8oZGRzX3Jlc3VsdF90YWJsZSwKICAgICAgICBsYWI9YXMuY2hhcmFjdGVyKGRkc19yZXN1bHRfdGFibGUkUmFuazkpLAogICAgICAgIHRpdGxlPSJQYWlyd2lzZSBjb21wYXJpc29ucyBvZiB0YXhhIChzcGVjaWVzIGxldmVsKSBiZXR3ZWVuIHRyZWF0bWVudHMiLAogICAgICAgIHg9J2xvZzJGb2xkQ2hhbmdlJywKICAgICAgICB5PSdwYWRqJywKICAgICAgICBsZWdlbmRQb3NpdGlvbiA9ICdib3R0b20nLAogICAgICAgIGxlZ2VuZExhYmVscz1jKCdOb3Qgc2lnLicsJ0xvZyAoYmFzZSAyKSBGQycsJ3BhZGotdmFsdWUnLCdwYWRqLXZhbHVlICYgTG9nIChiYXNlIDIpIEZDJyksCiAgICAgICAgcEN1dG9mZj0wLjA1LCAKICAgICAgICBGQ2N1dG9mZj0xCiAgICAgICAgKQpwcmludChwKQpnZ3NhdmUoInZvbGNhbm9fcGxvdC50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gcCwgcGF0aCA9ICIuL0RFU0VRMi8iKQpgYGAKIyMgQmV0YSBEaXZlcnNpdHkKTWVhc3VyaW5nIHNwZWNpZXMgZGl2ZXJzaXR5IG9yIHRoZSBsZXZlbCBvciBzaW1pbGFyaXR5L2Rpc3NpbWlsYXJpdHkgb2Ygc3BlY2llcyBiZXR3ZWVuIHNhbXBsZXMuCmBgYHtyfQojUGFpcndpc2UgQWRvbmlzIGZ1bmN0aW9uCnBhaXJ3aXNlLmFkb25pcy5kbSA8LSBmdW5jdGlvbih4LGZhY3RvcnMsc3RyYXR1bT1OVUxMLHAuYWRqdXN0Lm09ImZkciIscGVybT05OTkpewogIAogIGxpYnJhcnkodmVnYW4pCiAgaWYoY2xhc3MoeCkgIT0gImRpc3QiKSBzdG9wKCJ4IG11c3QgYmUgYSBkaXNzaW1pbGFyaXR5IG1hdHJpeCAoZGlzdCBvYmplY3QpIikKICBjbyA9IGFzLm1hdHJpeChjb21ibih1bmlxdWUoZmFjdG9ycyksMikpCiAgcGFpcnMgPSBjKCkKICBGLk1vZGVsID1jKCkKICBSMiA9IGMoKQogIHAudmFsdWUgPSBjKCkKICAKICAKICAKICBmb3IoZWxlbSBpbiAxOm5jb2woY28pKXsKICAgIHN1Yl9pbmRzIDwtIGZhY3RvcnMgJWluJSBjKGFzLmNoYXJhY3Rlcihjb1sxLGVsZW1dKSxhcy5jaGFyYWN0ZXIoY29bMixlbGVtXSkpCiAgICByZXNwIDwtIGFzLm1hdHJpeCh4KVtzdWJfaW5kcyxzdWJfaW5kc10KICAgIGFkID0gYWRvbmlzMihhcy5kaXN0KHJlc3ApIH4KICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgIGZhY3RvcnNbc3ViX2luZHNdLCBzdHJhdGE9c3RyYXR1bVtzdWJfaW5kc10sIHBlcm11dGF0aW9ucz1wZXJtKTsKICAgIAogICAgcGFpcnMgPSBjKHBhaXJzLHBhc3RlKGNvWzEsZWxlbV0sJ3ZzJyxjb1syLGVsZW1dKSk7CiAgICBGLk1vZGVsID1jKEYuTW9kZWwsYWQkRlsxXSk7CiAgICBSMiA9IGMoUjIsYWQkUjJbMV0pOwogICAgcC52YWx1ZSA9IGMocC52YWx1ZSxhZCRgUHIoPkYpYFsxXSkKICAgIAogIH0KICAKICBwLmFkanVzdGVkID0gcC5hZGp1c3QocC52YWx1ZSxtZXRob2Q9cC5hZGp1c3QubSkKICBwYWlydy5yZXMgPSBkYXRhLmZyYW1lKHBhaXJzLEYuTW9kZWwsUjIscC52YWx1ZSxwLmFkanVzdGVkKQogIHJldHVybihwYWlydy5yZXMpCn0KYGBgCgpgYGB7cn0KIyBDYWxjdWxhdGUgZGlzdGFuY2UgbWF0cmljZXMKcHNfYmMgPC0gcGh5bG9zZXE6OmRpc3RhbmNlKHBzX29iamVjdCwgbWV0aG9kID0gImJyYXkiKQpwc19ldWMgPC0gcGh5bG9zZXE6OmRpc3RhbmNlKHBzX29iamVjdCwgbWV0aG9kID0gImV1Y2xpZGVhbiIpCmBgYAojIyMgUEVSTUFOT1ZBcwpQRVJNQU5PVkEncyB3aXRoIEFkb25pcyAtICBQZXJtdXRhdGlvbmFsIE11bHRpdmFyaWF0ZSBBbmFseXNpcyBvZiBWYXJpYW5jZS4gVGhpcyBtZWFzdXJlcyBkaXNzaW1pbGFyaXR5IGluIHJlc3BvbnNlIHRvIG9uZSBvciBtb3JlIGZhY3RvcnMgaW4gYW4gYW5hbHlzaXMgb2YgdmFyaWFuY2UgZGVzaWduLiBEaXNzaW1pbGFyaXR5IHN0YXRpc3RpY3MgYXJlIHVzZWQgdG8gbWVhc3VyZSBkaXN0YW5jZXMgYmV0d2VlbiBkYXRhIHBvaW50cyBhbmQgdGVzdCB3aGV0aGVyIHRoZXkgYXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50LgoKV2UgcnVuIHRoZSBBZG9uaXMgdGVzdCBzcGVjaWZ5aW5nIHRoZSB0cmVhdG1lbnQgZ3JvdXBzIGluIHRoZSBtb2RlbCBmb3JtdWxhLiAKCiMjIyMgQnJheS1jdXJ0aXMKQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eSBleGFtaW5lcyB0aGUgYWJ1bmRhbmNlcyBvZiBBU1ZzIHRoYXQgYXJlIHNoYXJlZCBiZXR3ZWVuIHR3byBzYW1wbGVzLCBhbmQgdGhlIG51bWJlciBvZiBBU1ZzIGZvdW5kIGluIGVhY2guIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkgcmFuZ2VzIGZyb20gMC0xLiBJZiAwLCB0aGUgdHdvIHNhbXBsZXMgc2hhcmUgYWxsIHRoZSBzYW1lIEFTVnM7IGlmIDEsIHRoZXkgZG9u4oCZdCBzaGFyZSBhbnkgQVNWcy4KCiMjIyMgUGVybWFub3ZhIHJlc3VsdApUaGUgdmFsdWUgdW5kZXIgdGhlIGNvbHVtbiBsYWJlbGVkICdQcig+RiknIGluIHRoZSByZXN1bHRzIHRhYmxlIGluZGljYXRlcyBzaWduaWZpY2FuY2UgKGkuZS4gcC12YWx1ZSkKYGBge3J9CiNtYWtlIGEgZGF0YWZyYW1lIG91dCBvZiB0aGUgc2FtcGxlIGRhdGEKc2FtcGxlZGYgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShwc19vYmplY3QpKQoKYWRvbmlzMihwc19iYyB+IHRyZWF0bWVudCwgZGF0YSA9IHNhbXBsZWRmKSAKYGBgCiMjIyMgRXVjbGlkZWFuCk1lYXN1cmVzIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHR3byBzYW1wbGVzIGluIEV1Y2xpZGVhbiBzcGFjZSAodGhlIGxlbmd0aCBvZiB0aGUgbGluZSBzZWdtZW50IGJldHdlZW4gdGhlbSkuCgojIyMjIFBlcm1hbm92YSByZXN1bHQKVGhlIHZhbHVlIHVuZGVyIHRoZSBjb2x1bW4gbGFiZWxlZCAnUHIoPkYpJyBpbiB0aGUgcmVzdWx0cyB0YWJsZSBpbmRpY2F0ZXMgc2lnbmlmaWNhbmNlIChpLmUuIHAtdmFsdWUpCmBgYHtyfQphZG9uaXMyKHBzX2V1YyB+IHRyZWF0bWVudCwgZGF0YSA9IHNhbXBsZWRmKSAKYGBgCgojIyMgUGFpcndpc2UgY29tcGFyaXNvbnMKQSBtdWx0aS1sZXZlbCBBZG9uaXMgdGVzdCB1c2luZyB0aGUgRkRSIG11bHRpcGxlIHRlc3QgY29ycmVjdGlvbi4gCgojIyMjIEJyYXktY3VydGlzIHBhaXJ3aXNlIHJlc3VsdApgYGB7cn0KcGFpcndpc2UuYWRvbmlzLmRtKHBzX2JjLCBzYW1wbGVkZiR0cmVhdG1lbnQsIHAuYWRqdXN0Lm0gPSAiZmRyIikKCmBgYAojIyMjIEV1Y2xpZGVhbiBwYWlyd2lzZSByZXN1bHQKYGBge3J9CnBhaXJ3aXNlLmFkb25pcy5kbShwc19ldWMsIHNhbXBsZWRmJHRyZWF0bWVudCwgcC5hZGp1c3QubSA9ICJmZHIiKSAKCmBgYAojIyMgQmV0YSBkaXZlcnNpeSBQQ29BIGFuZCBOTURTIHBsb3RzClBDb0EgYW5kIE5NRFMgcGxvdHMgYXJlIHVzZWQgdG8gdmlzdWFsaXplIHRoZSBzaW1pbGFyaXRpZXMvZGlzc2ltaWxhcml0aWVzIG9mIHNhbXBsZSBwb2ludHMgdXNpbmcgdGhlaXIgY2FsY3VsYXRlZCBkaXN0YW5jZS9kaXNzaW1pbGFyaXR5IG1hdHJpY2VzIChmcm9tIHRoZSBCcmF5LWN1cnRpcyBhbmQgRXVjbGlkZWFuIGRpc3RhbmNlIG1lYXN1cmVtZW50cykuIFNhbXBsZXMgdGhhdCBhcmUgY2xvc2VyIGFyZSBtb3JlIHJlbGF0ZWQgYW5kIHZpY2UgdmVyc2EuIApQQ29BIHBsb3RzIG1heGltaXplIHRoZSBsaW5lYXIgY29ycmVsYXRpb24gYmV0d2VlbiBzYW1wbGVzLCB3aGVyZWluIE5NRFMgcGxvdHMgbWF4aW1pemUgdGhlIHJhbmstb3JkZXIgY29ycmVsYXRpb24gYmV0d2VlbiBzYW1wbGVzLiBBZGRpdGlvbmFsbHksIGluIGNhc2Ugb2YgTk1EUywgZGF0YSBpcyBub3QgcmVxdWlyZWQgdG8gZml0IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4KCkltYWdlcyBvZiBlYWNoIHBsb3QgY2FuIGJlIGZvdW5kIGluIHRoZSBzdGF0c19hbmFseXNpcy9iZXRhX2RpdmVyc2l0eV9wbG90cy8gZGlyZWN0b3J5LiAKCiMjIyMgQnJheS1jdXJ0aXMgUENvQQpgYGB7ciBCRF9icmF5LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD04fQojIEJyYXktY3VydGlzCiNQQ09BIEJDCnBzX2JjX3Bjb2EgPC0gb3JkaW5hdGUocHNfb2JqZWN0LCBkaXN0YW5jZSA9IHBzX2JjLCAiUENvQSIpCgpwc19iY19wY29hX3Bsb3QgPC0gcGxvdF9vcmRpbmF0aW9uKHBzX29iamVjdCwgcHNfYmNfcGNvYSwgY29sb3IgPSAidHJlYXRtZW50IikgKyAKICBnZW9tX3BvaW50KHNpemUgPSAzKSArIAogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiM5NTQ1MzUiLCAiIzcwMjk2MyIsICIjRjI4QzI4IiwgIiMwODhGOEYiKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpwc19iY19wY29hX3Bsb3QKCiNzYXZlIGFzIHRpZmYKZ2dzYXZlKCJicmF5X3Bjb2FfcGxvdC50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gcHNfYmNfcGNvYV9wbG90LCBwYXRoID0gIi4vYmV0YV9kaXZlcnNpdHlfcGxvdHMvIikKYGBgCiMjIyMgQnJheS1jdXJ0aXMgTk1EUwpgYGB7ciBCRF9icmF5Miwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCByZXN1bHRzPSdoaWRlJywgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9OH0KI05NRFMgQkMKcHNfYmNfbm1kcyA8LSBvcmRpbmF0ZShwc19vYmplY3QsIGRpc3RhbmNlID0gcHNfYmMsICJOTURTIikKCnBzX2JjX25tZHNfcGxvdCA8LSBwbG90X29yZGluYXRpb24ocHNfb2JqZWN0LCBwc19iY19ubWRzLCBjb2xvciA9ICJ0cmVhdG1lbnQiKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsgCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzk1NDUzNSIsICIjNzAyOTYzIiwgIiNGMjhDMjgiLCAiIzA4OEY4RiIpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCnBzX2JjX25tZHNfcGxvdAoKI3NhdmUgYXMgdGlmZgpnZ3NhdmUoImJyYXlfbm1kc19wbG90LnRpZmYiLCBkcGkgPSAzMDAsIHBsb3QgPSBwc19iY19ubWRzX3Bsb3QsIHBhdGggPSAiLi9iZXRhX2RpdmVyc2l0eV9wbG90cy8iKQpgYGAKIyMjIyBFdWNsaWRlYW4gUENvQQpgYGB7ciBCRF9ldWMsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgcmVzdWx0cz0naGlkZScsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTh9CgojIEV1Y2xpZGVhbgojUENPQSBFVUMKcHNfZXVjX3Bjb2EgPC0gb3JkaW5hdGUocHNfb2JqZWN0LCBkaXN0YW5jZSA9IHBzX2V1YywgIlBDb0EiKQoKcHNfZXVjX3Bjb2FfcGxvdCA8LSBwbG90X29yZGluYXRpb24ocHNfb2JqZWN0LCBwc19ldWNfcGNvYSwgY29sb3IgPSAidHJlYXRtZW50IikgKyAKICBnZW9tX3BvaW50KHNpemUgPSAzKSArIAogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiM5NTQ1MzUiLCAiIzcwMjk2MyIsICIjRjI4QzI4IiwgIiMwODhGOEYiKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpwc19ldWNfcGNvYV9wbG90Cgojc2F2ZSBhcyB0aWZmCmdnc2F2ZSgiZXVjX3Bjb2FfcGxvdC50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gcHNfZXVjX3Bjb2FfcGxvdCwgcGF0aCA9ICIuL2JldGFfZGl2ZXJzaXR5X3Bsb3RzLyIpCmBgYAojIyMjIEV1Y2xpZGVhbiBOTURTCmBgYHtyIEJEX2V1YzIsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgcmVzdWx0cz0naGlkZScsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTh9CiNOTURTIEJDCnBzX2V1Y19ubWRzIDwtIG9yZGluYXRlKHBzX29iamVjdCwgZGlzdGFuY2UgPSBwc19ldWMsICJOTURTIikKCnBzX2V1Y19ubWRzX3Bsb3QgPC0gcGxvdF9vcmRpbmF0aW9uKHBzX29iamVjdCwgcHNfZXVjX25tZHMsIGNvbG9yID0gInRyZWF0bWVudCIpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMykgKyAKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTU0NTM1IiwgIiM3MDI5NjMiLCAiI0YyOEMyOCIsICIjMDg4RjhGIikpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKcHNfZXVjX25tZHNfcGxvdAoKI3NhdmUgYXMgdGlmZgpnZ3NhdmUoImV1Y19ubWRzX3Bsb3QudGlmZiIsIGRwaSA9IDMwMCwgcGxvdCA9IHBzX2V1Y19ubWRzX3Bsb3QsIHBhdGggPSAiLi9iZXRhX2RpdmVyc2l0eV9wbG90cy8iKQpgYGAKCiMjIFJlbGF0aXZlIEFidW5kYW5jZSBUYXhhIFBsb3RzCiMjIyBSZWxhdGl2ZSBhYnVuZGFuY2UgdGF4YSBiYXIgcGxvdHMgZm9yIHRyZWF0bWVudApQbG90cyB3ZXJlIG1hZGUgYXQgdGhlIHBoeWx1bSwgZ2VudXMsIGFuZCBzcGVjaWVzIGxldmVsLCBjb21wYXJpbmcgYWNyb3NzIHRoZSA0IHRyZWF0bWVudHMuICAKCkltYWdlcyBvZiBlYWNoIHBsb3QgY2FuIGJlIGZvdW5kIGluIHRoZSBzdGF0c19hbmFseXNpcy90YXhhcGxvdHMvIGRpcmVjdG9yeS4gCgojIyMjIFBoeWx1bQpgYGB7ciBUYXhhcGxvdHNfcGh5LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD03fQojIHRyYW5zZm9ybSB0byByZWxhdGl2ZSBhYnVuZGFuY2UKcHNfcmVsIDwtIHRyYW5zZm9ybShwc19vYmplY3QsICJjb21wb3NpdGlvbmFsIikKCiMgbWVsdCB0aGUgZGF0YSBpbnRvIGEgdGFibGUKcHNfcmVsX21lbHQ8LSBwc19yZWwgJT4lCiAgcHNtZWx0KCkKCiMgR2V0IHBoeWx1bSB3aXRoIG1lYW4gcmVsYXRpdmUgYWJ1bmRhbmNlIGFjcm9zcyBhbGwgc2FtcGxlcyAKcHNfcmVsX3BoeWx1bV9zdW0gPC0gcHNfcmVsX21lbHQlPiUgZ3JvdXBfYnkoUmFuazMpICU+JSBkcGx5cjo6c3VtbWFyaXNlKEF2ZXIgPSBtZWFuKEFidW5kYW5jZSkpCm5hbWVzX3BzX3JlbF9waHlsdW0gPC0gcHNfcmVsX3BoeWx1bV9zdW0kUmFuazMKbmFtZXNfcHNfcmVsX3BoeWx1bQoKI1BoeWx1bSBQbG90CnRheGFwbG90X3BzX3JlbF9waHlsdW0gPSBnZ3Bsb3QocHNfcmVsX21lbHQKICAgICAgICAgICAgICAgICAgICAsIGFlcyh4ID0gdHJlYXRtZW50LCB5PUFidW5kYW5jZSkpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZmlsbCIsIGFlcyhmaWxsID0gUmFuazMpKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJhcXVhbWFyaW5lNCIsICJnb2xkIiwibGlnaHRwaW5rIiwgImZpcmVicmljayIsIiNEQTU3MjQiLCJpdm9yeTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmNoaWQiLCAiI0NCRDU4OCIsICIjODU2OUQ1IiwgIiNEMTQyODUiLCAiIzY1MjkyNiIsImdyZXk4MCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiM1RTczOEYiLCIjRDFBMzNEIiwgIiM4QTdDNjQiLCJsaWdodGdyZWVuIiwiYXF1YW1hcmluZTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhcXVhbWFyaW5lMiIsICJsaWdodHNhbG1vbiIsICIjQ0Q5QkNEIikpICsKICB0aGVtZV9idygpICsKICB5bGFiKCJSZWxhdGl2ZSBBYnVuZGFuY2UiKSArIHhsYWIoIlRyZWF0bWVudCIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3Q9MC41LCBoanVzdD0wKSkKdGF4YXBsb3RfcHNfcmVsX3BoeWx1bSA8LSB0YXhhcGxvdF9wc19yZWxfcGh5bHVtICsgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJQaHlsdW0iKSkKdGF4YXBsb3RfcHNfcmVsX3BoeWx1bQoKZ2dzYXZlKCJ0YXhhcGxvdF9waHlsdW0udGlmZiIsIGRwaSA9IDMwMCwgcGxvdCA9IHRheGFwbG90X3BzX3JlbF9waHlsdW0sIHBhdGggPSAiLi90YXhhcGxvdHMvIikKYGBgCiMjIyMgR2VudXMKR2VuZXJhIHdpdGggYSByZWxhdGl2ZSBhYnVuZGFuY2UgbG93ZXIgdGhhbiAwLjAwMDEgd2VyZSBncm91cGVkIHRvZ2V0aGVyLgpgYGB7ciBUYXhhcGxvdHNfZ2VuLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD03fQoKI0dldCBnZW5lcmEgd2l0aCBtZWFuIHJlYWx0aXZlIGFidW5kYW5jZSA+MC4wMDAxIGFjcm9zcyBhbGwgc2FtcGxlcyAKcHNfcmVsX2dlbnVzX3N1bSA8LSBwc19yZWxfbWVsdCU+JSBncm91cF9ieShSYW5rNykgJT4lIGRwbHlyOjpzdW1tYXJpc2UoQXZlciA9IG1lYW4oQWJ1bmRhbmNlKSkKcHNfcmVsX2dlbnVzX3N1YiA8LSBwc19yZWxfZ2VudXNfc3VtW3doaWNoKHBzX3JlbF9nZW51c19zdW0kQXZlciA+IDAuMDAwMSksXQpuYW1lc19wc19yZWxfZ2VudXMgPC0gcHNfcmVsX2dlbnVzX3N1YiRSYW5rNwpuYW1lc19wc19yZWxfZ2VudXMKCiMgUmVwbGFjZSBnZW5lcmEgd2l0aCA8MC4wMDEgYWJ1bmRhbmNlIHdpdGggIk5BIgpwc19yZWxfbWVsdCRSYW5rN1twc19yZWxfbWVsdCRSYW5rNyAhPSAiQWJpb3Ryb3BoaWEiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkFlcm9jb2NjdXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkRpYWxpc3RlciIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rNyAhPSAiR3JhbnVsaWNhdGVsbGEiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIklnbmF2aWJhY3Rlcml1bSIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rNyAhPSAiTGFjdGljYXNlaWJhY2lsbHVzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJMYWN0aWNhc2VpYmFjaWxsdXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkxhY3RpcGxhbnRpYmFjaWxsdXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkxhY3RvYmFjaWxsdXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkxhbmNlZmllbGRlbGxhIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJMZW50aWxhY3RvYmFjaWxsdXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkxldmlsYWN0b2JhY2lsbHVzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJMaW1vc2lsYWN0b2JhY2lsbHVzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJNZWdhc3BoYWVyYSIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rNyAhPSAiTW9yeWVsbGEiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIlNodXR0bGV3b3J0aGlhIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJTb2xvYmFjdGVyaXVtIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJTdGFwaHlsb2NvY2N1cyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rNyAhPSAiU3RyZXB0b2NvY2N1cyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rNyAhPSAiVmVpbGxvbmVsbGEiXSA8LSBOQQoKI3JlcGxhY2UgTkEgd2l0aCAiUmVsLiBBYnVuZC48MC4wMDAxIgpwc19yZWxfbWVsdFtpcy5uYShwc19yZWxfbWVsdCldPC0iUmVsLiBBYnVuZC48MC4wMDAxIgojR2VuZXJhIHBsb3QKdGF4YXBsb3RfcHNfcmVsX2dlbnVzID0gZ2dwbG90KHBzX3JlbF9tZWx0CiAgICAgICAgICAgICAgICAgICAgLCBhZXMoeCA9IHRyZWF0bWVudCwgeT1BYnVuZGFuY2UpKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249ImZpbGwiLCBhZXMoZmlsbCA9IFJhbms3KSkgICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiYXF1YW1hcmluZTQiLCAiZ29sZCIsImxpZ2h0cGluayIsICJmaXJlYnJpY2siLCIjREE1NzI0IiwiaXZvcnk0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAib3JjaGlkIiwgIiNDQkQ1ODgiLCAiIzg1NjlENSIsICIjRDE0Mjg1IiwgIiM2NTI5MjYiLCJncmV5ODAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjNUU3MzhGIiwiI0QxQTMzRCIsICIjOEE3QzY0IiwibGlnaHRncmVlbiIsImFxdWFtYXJpbmU0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYXF1YW1hcmluZTIiLCAibGlnaHRzYWxtb24iLCAiI0NEOUJDRCIpKSArCiAgdGhlbWVfYncoKSArCiAgeWxhYigiUmVsYXRpdmUgQWJ1bmRhbmNlIikgKyB4bGFiKCJUcmVhdG1lbnQiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0PTAuNSwgaGp1c3Q9MCkpCnRheGFwbG90X3BzX3JlbF9nZW51cyA8LSB0YXhhcGxvdF9wc19yZWxfZ2VudXMgKyBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkdlbnVzIikpCnRheGFwbG90X3BzX3JlbF9nZW51cwpnZ3NhdmUoInRheGFwbG90X2dlbnVzLnRpZmYiLCBkcGkgPSAzMDAsIHBsb3QgPSB0YXhhcGxvdF9wc19yZWxfZ2VudXMsIHBhdGggPSAiLi90YXhhcGxvdHMvIikKYGBgCiMjIyMgU3BlY2llcwpTcGVjaWVzIHdpdGggYSByZWxhdGl2ZSBhYnVuZGFuY2UgbG93ZXIgdGhhbiAwLjAxIHdlcmUgZ3JvdXBlZCB0b2dldGhlci4KYGBge3IgVGF4YXBsb3RzX3NwLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD03fQojR2V0IHNwZWNpZXMgd2l0aCBtZWFuIHJlYWx0aXZlIGFidW5kYW5jZSA+MC4wMSBhY3Jvc3MgYWxsIHNhbXBsZXMgCnBzX3JlbF9zcGVjaWVzX3N1bSA8LSBwc19yZWxfbWVsdCU+JSBncm91cF9ieShSYW5rOSkgJT4lIGRwbHlyOjpzdW1tYXJpc2UoQXZlciA9IG1lYW4oQWJ1bmRhbmNlKSkKcHNfcmVsX3NwZWNpZXNfc3ViIDwtIHBzX3JlbF9zcGVjaWVzX3N1bVt3aGljaChwc19yZWxfc3BlY2llc19zdW0kQXZlciA+IDAuMDEpLF0KbmFtZXNfcHNfcmVsX3NwZWNpZXMgPC0gcHNfcmVsX3NwZWNpZXNfc3ViJFJhbms5Cm5hbWVzX3BzX3JlbF9zcGVjaWVzCgojIFJlcGxhY2UgZ2VuZXJhIHdpdGggPDAuMDAxIGFidW5kYW5jZSB3aXRoICJOQSIKIyBSZXBsYWNlIGdlbmVyYSB3aXRoIDwwLjAwMSBhYnVuZGFuY2Ugd2l0aCAiTkEiCnBzX3JlbF9tZWx0JFJhbms5W3BzX3JlbF9tZWx0JFJhbms5ICE9ICJMYWN0b2JhY2lsbHVzIGNyaXNwYXR1cyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rOSAhPSAiTGFjdG9iYWNpbGx1cyBqZW5zZW5paSIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rOSAhPSAiTGltb3NpbGFjdG9iYWNpbGx1cyBmZXJtZW50dW0iICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazkgIT0gIkxpbW9zaWxhY3RvYmFjaWxsdXMgdmFnaW5hbGlzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms5ICE9ICJNZWdhc3BoYWVyYSBtaWNyb251Y2lmb3JtaXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazkgIT0gIlN0cmVwdG9jb2NjdXMgYW5naW5vc3VzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms5ICE9ICJTdHJlcHRvY29jY3VzIG11dGFucyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rOSAhPSAiU3RyZXB0b2NvY2N1cyBzYWxpdmFyaXVzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms5ICE9ICJTdHJlcHRvY29jY3VzIHZlc3RpYnVsYXJpcyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rOSAhPSAiVmVpbGxvbmVsbGEgYXR5cGljYSIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rOSAhPSAiVmVpbGxvbmVsbGEgZGlzcGFyIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms5ICE9ICJWZWlsbG9uZWxsYSBnZW5vbW9zcC4gUDEgb3JhbCBjbG9uZSBNQjVfUDE3IiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms5ICE9ICJWZWlsbG9uZWxsYSBzcC4gb3JhbCB0YXhvbiAxNTgiXSA8LSBOQQoKI3JlcGxhY2UgTkEgd2l0aCAiUmVsLiBBYnVuZC48MC4wMSIKcHNfcmVsX21lbHRbaXMubmEocHNfcmVsX21lbHQpXTwtIlJlbC4gQWJ1bmQuPDAuMDEiCiNTcGVjaWVzIHBsb3QKdGF4YXBsb3RfcHNfcmVsX3NwZWNpZXMgPSBnZ3Bsb3QocHNfcmVsX21lbHQKICAgICAgICAgICAgICAgICAgICAsIGFlcyh4ID0gdHJlYXRtZW50LCB5PUFidW5kYW5jZSkpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZmlsbCIsIGFlcyhmaWxsID0gUmFuazkpKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJhcXVhbWFyaW5lNCIsICJnb2xkIiwibGlnaHRwaW5rIiwgImZpcmVicmljayIsIiNEQTU3MjQiLCJpdm9yeTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmNoaWQiLCAiI0NCRDU4OCIsICIjODU2OUQ1IiwgIiNEMTQyODUiLCAiIzY1MjkyNiIsImdyZXk4MCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiM1RTczOEYiLCAiI0QxQTMzRCIpKSArCiAgdGhlbWVfYncoKSArCiAgeWxhYigiUmVsYXRpdmUgQWJ1bmRhbmNlIikgKyB4bGFiKCJUcmVhdG1lbnQiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0PTAuNSwgaGp1c3Q9MCkpCnRheGFwbG90X3BzX3JlbF9zcGVjaWVzIDwtIHRheGFwbG90X3BzX3JlbF9zcGVjaWVzICsgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJTcGVjaWVzIikpCnRheGFwbG90X3BzX3JlbF9zcGVjaWVzCmdnc2F2ZSgidGF4YXBsb3Rfc3BlY2llcy50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gdGF4YXBsb3RfcHNfcmVsX3NwZWNpZXMsIHBhdGggPSAiLi90YXhhcGxvdHMvIikKCmBgYAoKIyMjIFJlbGF0aXZlIGFidW5kYW5jZSB0b3AgMTAgdGF4YSBiYXIgcGxvdHMgcGVyIHNhbXBsZQpQbG90cyB3ZXJlIG1hZGUgYXQgdGhlIHBoeWx1bSwgZ2VudXMsIGFuZCBzcGVjaWVzIGxldmVsLCBjb21wYXJpbmcgYWNyb3NzIGFsbCBzYW1wbGVzLiAgCgpJbWFnZXMgb2YgZWFjaCBwbG90IGNhbiBiZSBmb3VuZCBpbiB0aGUgc3RhdHNfYW5hbHlzaXMvdGF4YXBsb3RzLyBkaXJlY3RvcnkuIAoKIyMjIyBUb3AgMTAgUGh5bGEKYGBge3IgVGF4YXBsb3RzMiwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCByZXN1bHRzPSdoaWRlJywgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTh9IAojIHRyYW5zZm9ybSB0byByZWxhdGl2ZSBhYnVuZGFuY2UKcHNfcmVsIDwtIHRyYW5zZm9ybShwc19vYmplY3QsICJjb21wb3NpdGlvbmFsIikKCiNUb3AgMTAgUEhZTEEKI0dldCBwaHlsdW0gbGV2ZWwKcHNfcGh5bHVtIDwtIHRheF9nbG9tKHBzX3JlbCwgdGF4cmFuaz0gIlJhbmszIikKI0dldCB0b3AgMTAgcGh5bHVtCnBoeWx1bV90b3AxMCA8LSBuYW1lcyhzb3J0KHRheGFfc3Vtcyhwc19waHlsdW0pLCBkZWNyZWFzaW5nPVRSVUUpKVsxOjEwXQpwc19waHlsdW1fdG9wMTAgPC0gcHJ1bmVfdGF4YShwaHlsdW1fdG9wMTAsIHBzX3BoeWx1bSkKCiMgbWVsdCB0aGUgZGF0YSBpbnRvIGEgdGFibGUKcHNfcGh5bHVtX21lbHQ8LSBwc19waHlsdW1fdG9wMTAgJT4lCiAgcHNtZWx0KCkKCiMgUGxvdCB0b3AgMTAgcGh5bHVtIGJ5IHNhbXBsZQp0YXhhcGxvdF9wc190b3AxMF9waHlsdW0gPSBnZ3Bsb3QocHNfcGh5bHVtX21lbHQKICAgICAgICAgICAgICAgICAgICAsIGFlcyh4ID0gc2FtcGxlLCB5PUFidW5kYW5jZSkpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZmlsbCIsIGFlcyhmaWxsID0gUmFuazMpKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJhcXVhbWFyaW5lNCIsICJnb2xkIiwibGlnaHRwaW5rIiwgImZpcmVicmljayIsIiNEQTU3MjQiLCJpdm9yeTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmNoaWQiLCAiI0NCRDU4OCIsICIjODU2OUQ1IiwgIiNEMTQyODUiKSkgKwogIHRoZW1lX2J3KCkgKwogIHlsYWIoIlJlbGF0aXZlIEFidW5kYW5jZSIpICsgeGxhYigiU2FtcGxlIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdD0wLjUsIGhqdXN0PTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NykpCnRheGFwbG90X3BzX3RvcDEwX3BoeWx1bSA8LSB0YXhhcGxvdF9wc190b3AxMF9waHlsdW0gKyBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IlRvcCAxMCBQaHlsYSIpKQp0YXhhcGxvdF9wc190b3AxMF9waHlsdW0KCmdnc2F2ZSgidGF4YXBsb3RfdG9wMTBfcGh5bHVtLnRpZmYiLCBkcGkgPSAzMDAsIHdpZHRoID0gMTgsIGhlaWdodCA9IDgsIHVuaXRzID0gImluIiwgcGxvdCA9IHRheGFwbG90X3BzX3RvcDEwX3BoeWx1bSwgcGF0aCA9ICIuL3RheGFwbG90cy8iKQpgYGAKIyMjIyBUb3AgMTAgR2VuZXJhCmBgYHtyIFRheGFwbG90c190b3BfZ2VuLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xOH0KCiNUb3AgMTAgR0VORVJBCiNHZXQgZ2VudXMgbGV2ZWwKcHNfZ2VudXMgPC0gdGF4X2dsb20ocHNfcmVsLCB0YXhyYW5rPSAiUmFuazciKQojR2V0IHRvcCAxMCBnZW5lcmEKZ2VudXNfdG9wMTAgPC0gbmFtZXMoc29ydCh0YXhhX3N1bXMocHNfZ2VudXMpLCBkZWNyZWFzaW5nPVRSVUUpKVsxOjEwXQpwc19nZW51c190b3AxMCA8LSBwcnVuZV90YXhhKGdlbnVzX3RvcDEwLCBwc19nZW51cykKCiMgbWVsdCB0aGUgZGF0YSBpbnRvIGEgdGFibGUKcHNfZ2VudXNfbWVsdDwtIHBzX2dlbnVzX3RvcDEwICU+JQogIHBzbWVsdCgpCiNoZWFkKHBzX2dlbnVzX21lbHQpCgojIFBsb3QgdG9wIDEwIHBoeWx1bSBieSBzYW1wbGUKdGF4YXBsb3RfcHNfdG9wMTBfZ2VudXMgPSBnZ3Bsb3QocHNfZ2VudXNfbWVsdAogICAgICAgICAgICAgICAgICAgICwgYWVzKHggPSBzYW1wbGUsIHk9QWJ1bmRhbmNlKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uPSJmaWxsIiwgYWVzKGZpbGwgPSBSYW5rNykpICArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImFxdWFtYXJpbmU0IiwgImdvbGQzIiwibGlnaHRwaW5rIiwgImZpcmVicmljayIsIiNEQTU3MjQiLCJpdm9yeTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmNoaWQiLCAiI0NCRDU4OCIsICIjODU2OUQ1IiwgIiNEMTQyODUiKSkgKwogIHRoZW1lX2J3KCkgKwogIHlsYWIoIlJlbGF0aXZlIEFidW5kYW5jZSIpICsgeGxhYigiU2FtcGxlIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdD0wLjUsIGhqdXN0PTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NykpCnRheGFwbG90X3BzX3RvcDEwX2dlbnVzIDwtIHRheGFwbG90X3BzX3RvcDEwX2dlbnVzICsgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJUb3AgMTAgR2VuZXJhIikpCnRheGFwbG90X3BzX3RvcDEwX2dlbnVzCgpnZ3NhdmUoInRheGFwbG90X3RvcDEwX2dlbnVzLnRpZmYiLCBkcGkgPSAzMDAsIHdpZHRoID0gMTgsIGhlaWdodCA9IDgsIHVuaXRzID0gImluIiwgcGxvdCA9IHRheGFwbG90X3BzX3RvcDEwX2dlbnVzLCBwYXRoID0gIi4vdGF4YXBsb3RzLyIpCmBgYAojIyMjIFRvcCAxMCBTcGVjaWVzCmBgYHtyIFRheGFwbG90c190b3Bfc3AsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgcmVzdWx0cz0naGlkZScsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE4fQoKI1RvcCAxMCBTUEVDSUVTCiNHZXQgc3BlY2llcyBsZXZlbApwc19zcGVjaWVzIDwtIHRheF9nbG9tKHBzX3JlbCwgdGF4cmFuaz0gIlJhbms5IikKI0dldCB0b3AgMTAgZ2VuZXJhCnNwZWNpZXNfdG9wMTAgPC0gbmFtZXMoc29ydCh0YXhhX3N1bXMocHNfc3BlY2llcyksIGRlY3JlYXNpbmc9VFJVRSkpWzE6MTBdCnBzX3NwZWNpZXNfdG9wMTAgPC0gcHJ1bmVfdGF4YShzcGVjaWVzX3RvcDEwLCBwc19zcGVjaWVzKQoKIyBtZWx0IHRoZSBkYXRhIGludG8gYSB0YWJsZQpwc19zcGVjaWVzX21lbHQ8LSBwc19zcGVjaWVzX3RvcDEwICU+JQogIHBzbWVsdCgpCiNoZWFkKHBzX3NwZWNpZXNfbWVsdCkKCiMgUGxvdCB0b3AgMTAgcGh5bHVtIGJ5IHNhbXBsZQp0YXhhcGxvdF9wc190b3AxMF9zcGVjaWVzID0gZ2dwbG90KHBzX3NwZWNpZXNfbWVsdAogICAgICAgICAgICAgICAgICAgICwgYWVzKHggPSBzYW1wbGUsIHk9QWJ1bmRhbmNlKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uPSJmaWxsIiwgYWVzKGZpbGwgPSBSYW5rOSkpICArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImFxdWFtYXJpbmU0IiwgImdvbGQzIiwibGlnaHRwaW5rIiwgImZpcmVicmljayIsIiNEQTU3MjQiLCJpdm9yeTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmNoaWQiLCAiI0NCRDU4OCIsICIjODU2OUQ1IiwgIiNEMTQyODUiKSkgKwogIHRoZW1lX2J3KCkgKwogIHlsYWIoIlJlbGF0aXZlIEFidW5kYW5jZSIpICsgeGxhYigiU2FtcGxlIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdD0wLjUsIGhqdXN0PTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NykpCnRheGFwbG90X3BzX3RvcDEwX3NwZWNpZXMgPC0gdGF4YXBsb3RfcHNfdG9wMTBfc3BlY2llcyArIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iVG9wIDEwIFNwZWNpZXMiKSkKdGF4YXBsb3RfcHNfdG9wMTBfc3BlY2llcwoKZ2dzYXZlKCJ0YXhhcGxvdF90b3AxMF9zcGVjaWVzLnRpZmYiLCBkcGkgPSAzMDAsIHdpZHRoID0gMTgsIGhlaWdodCA9IDgsIHVuaXRzID0gImluIiwgcGxvdCA9IHRheGFwbG90X3BzX3RvcDEwX3NwZWNpZXMsIHBhdGggPSAiLi90YXhhcGxvdHMvIikKCmBgYAo=